rdesktop-1.8.3/COPYING0000664000770100510440000010437411323031512013330 0ustar hean01hean01 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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. But first, please read . rdesktop-1.8.3/README0000664000770100510440000000322111551261314013152 0ustar hean01hean01========================================== rdesktop: A Remote Desktop Protocol client ========================================== rdesktop is an open source client for Microsoft's RDP protocol. It is known to work with Windows versions such as NT 4 Terminal Server, 2000, XP, 2003, 2003 R2, Vista, 2008, 7, and 2008 R2. rdesktop currently implements the RDP version 4 and 5 protocols. Installation ------------ rdesktop uses a GNU-style build procedure. Typically all that is necessary to install rdesktop is the following:: % ./configure % make % make install The default is to install under /usr/local. This can be changed by adding --prefix=directory to the configure line. Note for Subversion users ------------------------- If you have downloaded a snapshot of rdesktop using Subversion, you will first need to run ./bootstrap in order to generate the build infrastructure. This is not necessary for release versions of rdesktop. Invocation ---------- Simply run:: % rdesktop server where server is the name of the Terminal Services machine. (If you receive "Connection refused", this probably means that the server does not have Terminal Services enabled, or there is a firewall blocking access.) You can also specify a number of options on the command line. These are listed in the rdesktop manual page (run "man rdesktop"). Smart-card support notes ------------------------ The smart-card support module uses PCSC-lite. You should use PCSC-lite 1.2.9 or later. To enable smart-card support in the rdesktop just run "./configure" with the "--enable-smartcard" option. Also you can enable smart-card debug with additional "--with-debug-smartcard" option. rdesktop-1.8.3/configure0000775000770100510440000073057412424672435014235 0ustar hean01hean01#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for rdesktop 1.8.3. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rdesktop' PACKAGE_TARNAME='rdesktop' PACKAGE_VERSION='1.8.3' PACKAGE_STRING='rdesktop 1.8.3' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="rdesktop.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBICONV LIBOBJS SOUNDOBJ LIBSAMPLERATE_LIBS LIBSAMPLERATE_CFLAGS ALSA_LIBS ALSA_CFLAGS LIBAO_LIBS LIBAO_CFLAGS RDP2VNCTARGET VNCLINK LDVNC VNCINC SCARDOBJ PCSCLITE_LIBS PCSCLITE_CFLAGS XRANDR_LIBS XRANDR_CFLAGS CREDSSPOBJ GSSGLUE_LIBS GSSGLUE_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH ssldir STRIP PKG_CONFIG X_EXTRA_LIBS X_LIBS X_PRE_LIBS X_CFLAGS XMKMF EGREP GREP CPP INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_x with_openssl enable_static_openssl enable_credssp enable_static_gssglue enable_smartcard with_egd_socket with_libvncserver_config with_libvncserver with_sound enable_static_libsamplerate with_libiconv_prefix enable_largefile with_ipv6 with_debug with_debug_kbd with_debug_rdp5 with_debug_clipboard with_debug_sound with_debug_channel with_debug_seamless with_debug_smartcard with_debug_credssp ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP XMKMF PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR GSSGLUE_CFLAGS GSSGLUE_LIBS XRANDR_CFLAGS XRANDR_LIBS PCSCLITE_CFLAGS PCSCLITE_LIBS LIBAO_CFLAGS LIBAO_LIBS ALSA_CFLAGS ALSA_LIBS LIBSAMPLERATE_CFLAGS LIBSAMPLERATE_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures rdesktop 1.8.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/rdesktop] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of rdesktop 1.8.3:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-static-openssl link OpenSSL statically --disable-credssp disable support for CredSSP --enable-static-gssglue --disable-smartcard disable support for smartcard --enable-static-libsamplerate link libsamplerate statically --disable-largefile omit support for large files Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-x use the X Window System --with-openssl=DIR look for OpenSSL at DIR/include, DIR/lib --with-egd-socket=PATH look for Entropy Gathering Daemon socket at PATH --with-libvncserver-config=CMD use CMD as libvncserver-config --with-libvncserver make rdp2vnc --with-sound select sound system ("oss", "sgi", "sun", "alsa" or "libao") --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib --with-ipv6 enable IPv6-support --with-debug enable protocol debugging output --with-debug-kbd enable debugging of keyboard handling --with-debug-rdp5 enable debugging of RDP5 code --with-debug-clipboard enable debugging of clipboard code --with-debug-sound enable debugging of sound code --with-debug-channel enable debugging of virtual channel code --with-debug-seamless enable debugging of SeamlessRDP code --with-debug-smartcard enable debugging of smart-card code --with-debug-credssp enable debugging of CredSSP code Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path GSSGLUE_CFLAGS C compiler flags for GSSGLUE, overriding pkg-config GSSGLUE_LIBS linker flags for GSSGLUE, overriding pkg-config XRANDR_CFLAGS C compiler flags for XRANDR, overriding pkg-config XRANDR_LIBS linker flags for XRANDR, overriding pkg-config PCSCLITE_CFLAGS C compiler flags for PCSCLITE, overriding pkg-config PCSCLITE_LIBS linker flags for PCSCLITE, overriding pkg-config LIBAO_CFLAGS C compiler flags for LIBAO, overriding pkg-config LIBAO_LIBS linker flags for LIBAO, overriding pkg-config ALSA_CFLAGS C compiler flags for ALSA, overriding pkg-config ALSA_LIBS linker flags for ALSA, overriding pkg-config LIBSAMPLERATE_CFLAGS C compiler flags for LIBSAMPLERATE, overriding pkg-config LIBSAMPLERATE_LIBS linker flags for LIBSAMPLERATE, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF rdesktop configure 1.8.3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by rdesktop $as_me 1.8.3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test "$GCC" = yes; then CFLAGS="$CFLAGS -Wall" fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define B_ENDIAN 1" >>confdefs.h ;; #( no) $as_echo "#define L_ENDIAN 1" >>confdefs.h ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. $as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" # For Solaris; some versions of Sun CC require a space after -R and # others require no space. Words are not sufficient . . . . { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 $as_echo_n "checking whether -R must be followed by a space... " >&6; } ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" ac_xsave_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } X_LIBS="$X_LIBS -R$x_libraries" else LIBS="$ac_xsave_LIBS -R $x_libraries" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } X_LIBS="$X_LIBS -R $x_libraries" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 $as_echo "neither works" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_c_werror_flag=$ac_xsave_c_werror_flag LIBS=$ac_xsave_LIBS fi # Check for system-dependent libraries X programs must link with. # Do this before checking for the system-independent R6 libraries # (-lICE), since we may need -lsocket or whatever for X linking. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn Johnson says this is needed for Ultrix, if the X # libraries were built with DECnet support. And Karl Berry says # the Alpha needs dnet_stub (dnet does not exist). ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XOpenDisplay (); int main () { return XOpenDisplay (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_dnet_ntoa=yes else ac_cv_lib_dnet_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet_stub $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_stub_dnet_ntoa=yes else ac_cv_lib_dnet_stub_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_xsave_LIBS" # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) # needs -lnsl. # The nsl library prevents programs from opening the X display # on Irix 5.2, according to T.E. Dickey. # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = xyes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if ${ac_cv_lib_bsd_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_gethostbyname=yes else ac_cv_lib_bsd_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary # on later versions), says Simon Leinen: it contains gethostby* # variants that don't use the name server (or something). -lsocket # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes; then : fi if test $ac_cv_func_connect = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if ${ac_cv_lib_socket_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect=yes else ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes; then : X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi fi # Guillermo Gomez says -lposix is necessary on A/UX. ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" if test "x$ac_cv_func_remove" = xyes; then : fi if test $ac_cv_func_remove = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } if ${ac_cv_lib_posix_remove+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); int main () { return remove (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_posix_remove=yes else ac_cv_lib_posix_remove=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } if test "x$ac_cv_lib_posix_remove" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" if test "x$ac_cv_func_shmat" = xyes; then : fi if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } if ${ac_cv_lib_ipc_shmat+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lipc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); int main () { return shmat (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ipc_shmat=yes else ac_cv_lib_ipc_shmat=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } if test "x$ac_cv_lib_ipc_shmat" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS=$LDFLAGS test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # John Interrante, Karl Berry { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char IceConnectionNumber (); int main () { return IceConnectionNumber (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ICE_IceConnectionNumber=yes else ac_cv_lib_ICE_IceConnectionNumber=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi LDFLAGS=$ac_save_LDFLAGS fi if test "$no_x" = "yes"; then echo echo "ERROR: Could not find X Window System headers/libraries." if test -f /etc/debian_version; then echo "Probably you need to install the libx11-dev package." elif test -f /etc/redhat-release; then echo "Probably you need to install the libX11-devel package." fi echo "To specify paths manually, use the options --x-includes and --x-libraries." echo exit 1 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 $as_echo_n "checking for library containing socket... " >&6; } if ${ac_cv_search_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF for ac_lib in '' socket; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_socket=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_socket+:} false; then : break fi done if ${ac_cv_search_socket+:} false; then : else ac_cv_search_socket=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 $as_echo "$ac_cv_search_socket" >&6; } ac_res=$ac_cv_search_socket if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_aton" >&5 $as_echo_n "checking for library containing inet_aton... " >&6; } if ${ac_cv_search_inet_aton+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_aton (); int main () { return inet_aton (); ; return 0; } _ACEOF for ac_lib in '' resolv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_inet_aton=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_inet_aton+:} false; then : break fi done if ${ac_cv_search_inet_aton+:} false; then : else ac_cv_search_inet_aton=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5 $as_echo "$ac_cv_search_inet_aton" >&6; } ac_res=$ac_cv_search_inet_aton if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi ac_fn_c_check_header_mongrel "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" if test "x$ac_cv_header_sys_select_h" = xyes; then : $as_echo "#define HAVE_SYS_SELECT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/modem.h" "ac_cv_header_sys_modem_h" "$ac_includes_default" if test "x$ac_cv_header_sys_modem_h" = xyes; then : $as_echo "#define HAVE_SYS_MODEM_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/filio.h" "ac_cv_header_sys_filio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_filio_h" = xyes; then : $as_echo "#define HAVE_SYS_FILIO_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/strtio.h" "ac_cv_header_sys_strtio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_strtio_h" = xyes; then : $as_echo "#define HAVE_SYS_STRTIO_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" if test "x$ac_cv_header_locale_h" = xyes; then : $as_echo "#define HAVE_LOCALE_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" if test "x$ac_cv_header_langinfo_h" = xyes; then : $as_echo "#define HAVE_LANGINFO_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sysexits.h" "ac_cv_header_sysexits_h" "$ac_includes_default" if test "x$ac_cv_header_sysexits_h" = xyes; then : $as_echo "#define HAVE_SYSEXITS_H 1" >>confdefs.h fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi # # OpenSSL detection borrowed from stunnel # checkssldir() { : if test -f "$1/include/openssl/ssl.h"; then ssldir="$1" return 0 fi return 1 } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL directory" >&5 $as_echo_n "checking for OpenSSL directory... " >&6; } # Check whether --with-openssl was given. if test "${with_openssl+set}" = set; then : withval=$with_openssl; checkssldir "$withval" else for maindir in /usr/local /usr/lib /usr/pkg /usr /var/ssl /opt; do for dir in $maindir $maindir/openssl $maindir/ssl; do checkssldir $dir && break 2 done done fi if test -z "$ssldir"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not found" >&5 $as_echo "Not found" >&6; } echo echo "ERROR: Could not find OpenSSL headers/libraries." if test -f /etc/debian_version; then echo "Probably you need to install the libssl-dev package." elif test -f /etc/redhat-release; then echo "Probably you need to install the openssl-devel package." fi echo "To specify a path manually, use the --with-openssl option." echo exit 1 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssldir" >&5 $as_echo "$ssldir" >&6; } cat >>confdefs.h <<_ACEOF #define ssldir "$ssldir" _ACEOF CFLAGS="$CFLAGS -I$ssldir/include" # Check whether --enable-static-openssl was given. if test "${enable_static_openssl+set}" = set; then : enableval=$enable_static_openssl; static_openssl=yes else static_openssl=no fi if test x"$static_openssl" = "xyes"; then # OpenSSL generally relies on libz { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing deflate" >&5 $as_echo_n "checking for library containing deflate... " >&6; } if ${ac_cv_search_deflate+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char deflate (); int main () { return deflate (); ; return 0; } _ACEOF for ac_lib in '' z; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_deflate=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_deflate+:} false; then : break fi done if ${ac_cv_search_deflate+:} false; then : else ac_cv_search_deflate=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_deflate" >&5 $as_echo "$ac_cv_search_deflate" >&6; } ac_res=$ac_cv_search_deflate if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi LIBS="-L$ssldir/lib -L$ssldir/lib64 -Wl,-Bstatic -lssl -lcrypto -Wl,-Bdynamic $LIBS" else LIBS="-L$ssldir/lib -L$ssldir/lib64 -lssl -lcrypto $LIBS" # # target-specific stuff # case "$host" in *-*-solaris*) LDFLAGS="$LDFLAGS -R$ssldir/lib" ;; *-dec-osf*) LDFLAGS="$LDFLAGS -Wl,-rpath,$ssldir/lib" ;; esac fi # Check whether --enable-credssp was given. if test "${enable_credssp+set}" = set; then : enableval=$enable_credssp; fi # Check whether --enable-static-gssglue was given. if test "${enable_static_gssglue+set}" = set; then : enableval=$enable_static_gssglue; static_gssglue=yes else static_gssglue=no fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi if test "x$enable_credssp" != "xno"; then : if test -n "$PKG_CONFIG"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GSSGLUE" >&5 $as_echo_n "checking for GSSGLUE... " >&6; } if test -n "$GSSGLUE_CFLAGS"; then pkg_cv_GSSGLUE_CFLAGS="$GSSGLUE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libgssglue\""; } >&5 ($PKG_CONFIG --exists --print-errors "libgssglue") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GSSGLUE_CFLAGS=`$PKG_CONFIG --cflags "libgssglue" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$GSSGLUE_LIBS"; then pkg_cv_GSSGLUE_LIBS="$GSSGLUE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libgssglue\""; } >&5 ($PKG_CONFIG --exists --print-errors "libgssglue") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GSSGLUE_LIBS=`$PKG_CONFIG --libs "libgssglue" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GSSGLUE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libgssglue" 2>&1` else GSSGLUE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libgssglue" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$GSSGLUE_PKG_ERRORS" >&5 WITH_CREDSSP=0 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } WITH_CREDSSP=0 else GSSGLUE_CFLAGS=$pkg_cv_GSSGLUE_CFLAGS GSSGLUE_LIBS=$pkg_cv_GSSGLUE_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } WITH_CREDSSP=1 fi fi if test x"$WITH_CREDSSP" = "x1"; then CREDSSPOBJ="cssp.o" CFLAGS="$CFLAGS $GSSGLUE_CFLAGS" if test "x$static_gssglue" != "xno"; then : LIBS="$LIBS -Wl,-Bstatic -lgssglue -Wl,-Bdynamic" else LIBS="$LIBS -lgssglue" fi $as_echo "#define WITH_CREDSSP 1" >>confdefs.h else echo echo "CredSSP support requires libgssglue, install the dependency" echo "or disable the feature using --disable-credssp." echo exit 1 fi fi # xrandr if test -n "$PKG_CONFIG"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XRANDR" >&5 $as_echo_n "checking for XRANDR... " >&6; } if test -n "$XRANDR_CFLAGS"; then pkg_cv_XRANDR_CFLAGS="$XRANDR_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xrandr\""; } >&5 ($PKG_CONFIG --exists --print-errors "xrandr") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_XRANDR_CFLAGS=`$PKG_CONFIG --cflags "xrandr" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$XRANDR_LIBS"; then pkg_cv_XRANDR_LIBS="$XRANDR_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xrandr\""; } >&5 ($PKG_CONFIG --exists --print-errors "xrandr") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_XRANDR_LIBS=`$PKG_CONFIG --libs "xrandr" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then XRANDR_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xrandr" 2>&1` else XRANDR_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xrandr" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$XRANDR_PKG_ERRORS" >&5 HAVE_XRANDR=0 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } HAVE_XRANDR=0 else XRANDR_CFLAGS=$pkg_cv_XRANDR_CFLAGS XRANDR_LIBS=$pkg_cv_XRANDR_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_XRANDR=1 fi fi if test x"$HAVE_XRANDR" = "x1"; then CFLAGS="$CFLAGS $XRANDR_CFLAGS" LIBS="$LIBS $XRANDR_LIBS" $as_echo "#define HAVE_XRANDR 1" >>confdefs.h fi # Check whether --enable-smartcard was given. if test "${enable_smartcard+set}" = set; then : enableval=$enable_smartcard; fi if test "x$enable_smartcard" != "xno"; then : case "$OSTYPE" in darwin*) ac_fn_c_check_header_mongrel "$LINENO" "PCSC/pcsclite.h" "ac_cv_header_PCSC_pcsclite_h" "$ac_includes_default" if test "x$ac_cv_header_PCSC_pcsclite_h" = xyes; then : WITH_SCARD=1 else WITH_SCARD=0 fi PCSCLITE_CFLAGS="" PCSCLITE_LIBS="-framework PCSC" ;; *) if test -n "$PKG_CONFIG"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PCSCLITE" >&5 $as_echo_n "checking for PCSCLITE... " >&6; } if test -n "$PCSCLITE_CFLAGS"; then pkg_cv_PCSCLITE_CFLAGS="$PCSCLITE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcsclite\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpcsclite") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PCSCLITE_CFLAGS=`$PKG_CONFIG --cflags "libpcsclite" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PCSCLITE_LIBS"; then pkg_cv_PCSCLITE_LIBS="$PCSCLITE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpcsclite\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpcsclite") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PCSCLITE_LIBS=`$PKG_CONFIG --libs "libpcsclite" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PCSCLITE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpcsclite" 2>&1` else PCSCLITE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpcsclite" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PCSCLITE_PKG_ERRORS" >&5 WITH_SCARD=0 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } WITH_SCARD=0 else PCSCLITE_CFLAGS=$pkg_cv_PCSCLITE_CFLAGS PCSCLITE_LIBS=$pkg_cv_PCSCLITE_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } WITH_SCARD=1 fi fi ;; esac if test x"$WITH_SCARD" = "x1"; then SCARDOBJ="scard.o" CFLAGS="$CFLAGS $PCSCLITE_CFLAGS" LIBS="$LIBS $PCSCLITE_LIBS" $as_echo "#define WITH_SCARD 1" >>confdefs.h else echo echo "SmartCard support requires PCSC, install the dependency" echo "or disable the feature using --disable-smartcard." echo exit 1 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for old version of PCSC" >&5 $as_echo_n "checking for old version of PCSC... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef __APPLE__ #include #include #else #include #endif int main () { SCardControl(NULL, NULL, 0, NULL, NULL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define WITH_PCSC120 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # # Alignment # { $as_echo "$as_me:${as_lineno-$LINENO}: checking if architecture needs alignment" >&5 $as_echo_n "checking if architecture needs alignment... " >&6; } if test "$cross_compiling" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming yes" >&5 $as_echo "assuming yes" >&6; } $as_echo "#define NEED_ALIGN 1" >>confdefs.h else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main(int argc, char **argv) { unsigned char test[8] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; signal(SIGBUS, exit); signal(SIGABRT, exit); signal(SIGSEGV, exit); if (*((unsigned int *)(test + 1)) != 0x55443322 && *((unsigned int *)(test + 1)) != 0x22334455) { return 1; } return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define NEED_ALIGN 1" >>confdefs.h fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi # # EGD # # Check whether --with-egd-socket was given. if test "${with_egd_socket+set}" = set; then : withval=$with_egd_socket; EGD_SOCKET="$withval" else EGD_SOCKET="/var/run/egd-pool" fi cat >>confdefs.h <<_ACEOF #define EGD_SOCKET "$EGD_SOCKET" _ACEOF # # rdp2vnc # vncserverconfig=libvncserver-config # Check whether --with-libvncserver-config was given. if test "${with_libvncserver_config+set}" = set; then : withval=$with_libvncserver_config; vncserverconfig="$withval" fi # Check whether --with-libvncserver was given. if test "${with_libvncserver+set}" = set; then : withval=$with_libvncserver; VNCINC=`$vncserverconfig --cflags` LDVNC=`$vncserverconfig --libs` VNCLINK=`$vncserverconfig --link` RDP2VNCTARGET="rdp2vnc" fi # # sound # sound="yes" # Check whether --with-sound was given. if test "${with_sound+set}" = set; then : withval=$with_sound; sound="$withval" fi ac_fn_c_check_header_mongrel "$LINENO" "sys/soundcard.h" "ac_cv_header_sys_soundcard_h" "$ac_includes_default" if test "x$ac_cv_header_sys_soundcard_h" = xyes; then : HAVE_OSS=1 else HAVE_OSS=0 fi ac_fn_c_check_header_mongrel "$LINENO" "dmedia/audio.h" "ac_cv_header_dmedia_audio_h" "$ac_includes_default" if test "x$ac_cv_header_dmedia_audio_h" = xyes; then : HAVE_SGI=1 else HAVE_SGI=0 fi ac_fn_c_check_header_mongrel "$LINENO" "sys/audioio.h" "ac_cv_header_sys_audioio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_audioio_h" = xyes; then : HAVE_SUN=1 else HAVE_SUN=0 fi # Check whether --enable-static-libsamplerate was given. if test "${enable_static_libsamplerate+set}" = set; then : enableval=$enable_static_libsamplerate; static_libsamplerate=yes else static_libsamplerate=no fi if test -n "$PKG_CONFIG"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBAO" >&5 $as_echo_n "checking for LIBAO... " >&6; } if test -n "$LIBAO_CFLAGS"; then pkg_cv_LIBAO_CFLAGS="$LIBAO_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ao\""; } >&5 ($PKG_CONFIG --exists --print-errors "ao") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBAO_CFLAGS=`$PKG_CONFIG --cflags "ao" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBAO_LIBS"; then pkg_cv_LIBAO_LIBS="$LIBAO_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ao\""; } >&5 ($PKG_CONFIG --exists --print-errors "ao") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBAO_LIBS=`$PKG_CONFIG --libs "ao" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBAO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ao" 2>&1` else LIBAO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ao" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBAO_PKG_ERRORS" >&5 HAVE_LIBAO=0 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } HAVE_LIBAO=0 else LIBAO_CFLAGS=$pkg_cv_LIBAO_CFLAGS LIBAO_LIBS=$pkg_cv_LIBAO_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_LIBAO=1 fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ALSA" >&5 $as_echo_n "checking for ALSA... " >&6; } if test -n "$ALSA_CFLAGS"; then pkg_cv_ALSA_CFLAGS="$ALSA_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5 ($PKG_CONFIG --exists --print-errors "alsa") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ALSA_CFLAGS=`$PKG_CONFIG --cflags "alsa" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$ALSA_LIBS"; then pkg_cv_ALSA_LIBS="$ALSA_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5 ($PKG_CONFIG --exists --print-errors "alsa") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ALSA_LIBS=`$PKG_CONFIG --libs "alsa" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then ALSA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "alsa" 2>&1` else ALSA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "alsa" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$ALSA_PKG_ERRORS" >&5 HAVE_ALSA=0 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } HAVE_ALSA=0 else ALSA_CFLAGS=$pkg_cv_ALSA_CFLAGS ALSA_LIBS=$pkg_cv_ALSA_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_ALSA=1 fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSAMPLERATE" >&5 $as_echo_n "checking for LIBSAMPLERATE... " >&6; } if test -n "$LIBSAMPLERATE_CFLAGS"; then pkg_cv_LIBSAMPLERATE_CFLAGS="$LIBSAMPLERATE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"samplerate\""; } >&5 ($PKG_CONFIG --exists --print-errors "samplerate") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBSAMPLERATE_CFLAGS=`$PKG_CONFIG --cflags "samplerate" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBSAMPLERATE_LIBS"; then pkg_cv_LIBSAMPLERATE_LIBS="$LIBSAMPLERATE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"samplerate\""; } >&5 ($PKG_CONFIG --exists --print-errors "samplerate") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBSAMPLERATE_LIBS=`$PKG_CONFIG --libs "samplerate" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBSAMPLERATE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "samplerate" 2>&1` else LIBSAMPLERATE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "samplerate" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBSAMPLERATE_PKG_ERRORS" >&5 HAVE_LIBSAMPLERATE=0 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } HAVE_LIBSAMPLERATE=0 else LIBSAMPLERATE_CFLAGS=$pkg_cv_LIBSAMPLERATE_CFLAGS LIBSAMPLERATE_LIBS=$pkg_cv_LIBSAMPLERATE_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_LIBSAMPLERATE=1 fi if test x"$HAVE_LIBSAMPLERATE" = "x1"; then $as_echo "#define HAVE_LIBSAMPLERATE 1" >>confdefs.h if test x"$static_libsamplerate" = "xyes"; then _libsamplerate_libdir=`$PKG_CONFIG --errors-to-stdout --variable=libdir samplerate` LIBSAMPLERATE_LIBS="$_libsamplerate_libdir""/libsamplerate.a" LIBSAMPLERATE_LIBS="$LIBSAMPLERATE_LIBS -lm" fi fi fi if test "$sound" != "no"; then SOUNDOBJ="$SOUNDOBJ rdpsnd.o rdpsnd_dsp.o" CFLAGS="$CFLAGS $LIBSAMPLERATE_CFLAGS" LIBS="$LIBS $LIBSAMPLERATE_LIBS" $as_echo "#define WITH_RDPSND 1" >>confdefs.h fi case $sound in yes) if test x"$HAVE_OSS" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_oss.o" $as_echo "#define RDPSND_OSS 1" >>confdefs.h fi if test x"$HAVE_SGI" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_sgi.o" LIBS="$LIBS -laudio" $as_echo "#define RDPSND_SGI 1" >>confdefs.h fi if test x"$HAVE_SUN" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_sun.o" $as_echo "#define RDPSND_SUN 1" >>confdefs.h fi if test x"$HAVE_ALSA" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_alsa.o" CFLAGS="$CFLAGS $ALSA_CFLAGS" LIBS="$LIBS $ALSA_LIBS" $as_echo "#define RDPSND_ALSA 1" >>confdefs.h fi if test x"$HAVE_LIBAO" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_libao.o" CFLAGS="$CFLAGS $LIBAO_CFLAGS" LIBS="$LIBS $LIBAO_LIBS" $as_echo "#define RDPSND_LIBAO 1" >>confdefs.h fi ;; oss) if test x"$HAVE_OSS" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_oss.o" $as_echo "#define RDPSND_OSS 1" >>confdefs.h else as_fn_error $? "Selected sound system is not available." "$LINENO" 5 fi ;; sgi) if test x"$HAVE_SGI" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_sgi.o" LIBS="$LIBS -laudio" $as_echo "#define RDPSND_SGI 1" >>confdefs.h else as_fn_error $? "Selected sound system is not available." "$LINENO" 5 fi ;; sun) if test x"$HAVE_SUN" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_sun.o" $as_echo "#define RDPSND_SUN 1" >>confdefs.h else as_fn_error $? "Selected sound system is not available." "$LINENO" 5 fi ;; alsa) if test x"$HAVE_ALSA" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_alsa.o" CFLAGS="$CFLAGS $ALSA_CFLAGS" LIBS="$LIBS $ALSA_LIBS" $as_echo "#define RDPSND_ALSA 1" >>confdefs.h else as_fn_error $? "Selected sound system is not available." "$LINENO" 5 fi ;; libao) if test x"$HAVE_LIBAO" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_libao.o" CFLAGS="$CFLAGS $LIBAO_CFLAGS" LIBS="$LIBS $LIBAO_LIBS" $as_echo "#define RDPSND_LIBAO 1" >>confdefs.h else as_fn_error $? "Selected sound system is not available." "$LINENO" 5 fi ;; no) ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: sound support disabled" >&5 $as_echo "$as_me: WARNING: sound support disabled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Currently supported systems are Open Sound System (oss), SGI AL (sgi), Sun/BSD (sun), ALSA (alsa) and libao" >&5 $as_echo "$as_me: WARNING: Currently supported systems are Open Sound System (oss), SGI AL (sgi), Sun/BSD (sun), ALSA (alsa) and libao" >&2;} ;; esac # # dirfd # ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi dirfd_headers=' #if HAVE_DIRENT_H # include #else /* not HAVE_DIRENT_H */ # define dirent direct # if HAVE_SYS_NDIR_H # include # endif /* HAVE_SYS_NDIR_H */ # if HAVE_SYS_DIR_H # include # endif /* HAVE_SYS_DIR_H */ # if HAVE_NDIR_H # include # endif /* HAVE_NDIR_H */ #endif /* HAVE_DIRENT_H */ ' for ac_func in dirfd do : ac_fn_c_check_func "$LINENO" "dirfd" "ac_cv_func_dirfd" if test "x$ac_cv_func_dirfd" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DIRFD 1 _ACEOF fi done ac_fn_c_check_decl "$LINENO" "dirfd" "ac_cv_have_decl_dirfd" "$dirfd_headers " if test "x$ac_cv_have_decl_dirfd" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_DIRFD $ac_have_decl _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dirfd is a macro" >&5 $as_echo_n "checking whether dirfd is a macro... " >&6; } if ${jm_cv_func_dirfd_macro+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $dirfd_headers #ifdef dirfd dirent_header_defines_dirfd #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "dirent_header_defines_dirfd" >/dev/null 2>&1; then : jm_cv_func_dirfd_macro=yes else jm_cv_func_dirfd_macro=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $jm_cv_func_dirfd_macro" >&5 $as_echo "$jm_cv_func_dirfd_macro" >&6; } # Use the replacement only if we have no function, macro, # or declaration with that name. if test $ac_cv_func_dirfd,$ac_cv_have_decl_dirfd,$jm_cv_func_dirfd_macro \ = no,no,no; then ac_fn_c_check_func "$LINENO" "dirfd" "ac_cv_func_dirfd" if test "x$ac_cv_func_dirfd" = xyes; then : $as_echo "#define HAVE_DIRFD 1" >>confdefs.h else case " $LIBOBJS " in *" dirfd.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS dirfd.$ac_objext" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to get the file descriptor associated with an open DIR*" >&5 $as_echo_n "checking how to get the file descriptor associated with an open DIR*... " >&6; } if ${gl_cv_sys_dir_fd_member_name+:} false; then : $as_echo_n "(cached) " >&6 else dirfd_save_CFLAGS=$CFLAGS for ac_expr in d_fd dd_fd; do CFLAGS="$CFLAGS -DDIR_FD_MEMBER_NAME=$ac_expr" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $dirfd_headers int main () { DIR *dir_p = opendir("."); (void) dir_p->DIR_FD_MEMBER_NAME; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dir_fd_found=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$dirfd_save_CFLAGS test "$dir_fd_found" = yes && break done test "$dir_fd_found" = yes || ac_expr=no_such_member gl_cv_sys_dir_fd_member_name=$ac_expr fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_dir_fd_member_name" >&5 $as_echo "$gl_cv_sys_dir_fd_member_name" >&6; } if test $gl_cv_sys_dir_fd_member_name != no_such_member; then cat >>confdefs.h <<_ACEOF #define DIR_FD_MEMBER_NAME $gl_cv_sys_dir_fd_member_name _ACEOF fi fi # # iconv # # Check whether --with-libiconv-prefix was given. if test "${with_libiconv_prefix+set}" = set; then : withval=$with_libiconv_prefix; for dir in `echo "$withval" | tr : ' '`; do if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi done fi ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default" if test "x$ac_cv_header_iconv_h" = xyes; then : $as_echo "#define HAVE_ICONV_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 $as_echo_n "checking for iconv... " >&6; } if ${am_cv_func_iconv+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS -liconv" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_lib_iconv=yes am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$am_save_LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 $as_echo "$am_cv_func_iconv" >&6; } if test "$am_cv_func_iconv" = yes; then $as_echo "#define HAVE_ICONV 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 $as_echo_n "checking for iconv declaration... " >&6; } if ${am_cv_proto_iconv+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : am_cv_proto_iconv_arg1="" else am_cv_proto_iconv_arg1="const" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" fi am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- }$am_cv_proto_iconv" >&5 $as_echo "${ac_t:- }$am_cv_proto_iconv" >&6; } cat >>confdefs.h <<_ACEOF #define ICONV_CONST $am_cv_proto_iconv_arg1 _ACEOF fi LIBICONV= if test "$am_cv_lib_iconv" = yes; then LIBICONV="-liconv" fi LIBS="$LIBS $LIBICONV" # # socklen_t # from curl ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include #include " if test "x$ac_cv_type_socklen_t" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t equivalent" >&5 $as_echo_n "checking for socklen_t equivalent... " >&6; } if ${socklen_t_cv_equiv+:} false; then : $as_echo_n "(cached) " >&6 else # Systems have either "struct sockaddr *" or # "void *" as the second argument to getpeername socklen_t_cv_equiv= for arg2 in "struct sockaddr" void; do for t in int size_t unsigned long "unsigned long"; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int getpeername (int, $arg2 *, $t *); int main () { $t len; getpeername(0,0,&len); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : socklen_t_cv_equiv="$t" break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done done if test "x$socklen_t_cv_equiv" = x; then as_fn_error $? "Cannot find a type to use in place of socklen_t" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $socklen_t_cv_equiv" >&5 $as_echo "$socklen_t_cv_equiv" >&6; } cat >>confdefs.h <<_ACEOF #define socklen_t $socklen_t_cv_equiv _ACEOF fi # # statfs stuff # for ac_header in sys/vfs.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/vfs.h" "ac_cv_header_sys_vfs_h" "$ac_includes_default" if test "x$ac_cv_header_sys_vfs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_VFS_H 1 _ACEOF fi done for ac_header in sys/statvfs.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default" if test "x$ac_cv_header_sys_statvfs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_STATVFS_H 1 _ACEOF fi done for ac_header in sys/statfs.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/statfs.h" "ac_cv_header_sys_statfs_h" "$ac_includes_default" if test "x$ac_cv_header_sys_statfs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_STATFS_H 1 _ACEOF fi done for ac_header in sys/param.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PARAM_H 1 _ACEOF fi done mount_includes="\ $ac_includes_default #if HAVE_SYS_PARAM_H # include #endif " for ac_header in sys/mount.h do : ac_fn_c_check_header_compile "$LINENO" "sys/mount.h" "ac_cv_header_sys_mount_h" "$mount_includes " if test "x$ac_cv_header_sys_mount_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_MOUNT_H 1 _ACEOF fi done ################################################# # these tests are taken from the GNU fileutils package { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to get filesystem space usage..." >&5 $as_echo "$as_me: checking how to get filesystem space usage..." >&6;} space=no # Test for statvfs64. if test $space = no; then # SVR4 { $as_echo "$as_me:${as_lineno-$LINENO}: checking statvfs64 function (SVR4)" >&5 $as_echo_n "checking statvfs64 function (SVR4)... " >&6; } if ${fu_cv_sys_stat_statvfs64+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : fu_cv_sys_stat_statvfs64=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined(HAVE_UNISTD_H) #include #endif #include #include main () { struct statvfs64 fsd; exit (statvfs64 (".", &fsd)); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : fu_cv_sys_stat_statvfs64=yes else fu_cv_sys_stat_statvfs64=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statvfs64" >&5 $as_echo "$fu_cv_sys_stat_statvfs64" >&6; } if test $fu_cv_sys_stat_statvfs64 = yes; then space=yes $as_echo "#define STAT_STATVFS64 1" >>confdefs.h fi fi # Perform only the link test since it seems there are no variants of the # statvfs function. This check is more than just AC_CHECK_FUNCS(statvfs) # because that got a false positive on SCO OSR5. Adding the declaration # of a `struct statvfs' causes this test to fail (as it should) on such # systems. That system is reported to work fine with STAT_STATFS4 which # is what it gets when this test fails. if test $space = no; then # SVR4 { $as_echo "$as_me:${as_lineno-$LINENO}: checking statvfs function (SVR4)" >&5 $as_echo_n "checking statvfs function (SVR4)... " >&6; } if ${fu_cv_sys_stat_statvfs+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct statvfs fsd; statvfs (0, &fsd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : fu_cv_sys_stat_statvfs=yes else fu_cv_sys_stat_statvfs=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statvfs" >&5 $as_echo "$fu_cv_sys_stat_statvfs" >&6; } if test $fu_cv_sys_stat_statvfs = yes; then space=yes $as_echo "#define STAT_STATVFS 1" >>confdefs.h fi fi if test $space = no; then # DEC Alpha running OSF/1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 3-argument statfs function (DEC OSF/1)" >&5 $as_echo_n "checking for 3-argument statfs function (DEC OSF/1)... " >&6; } if ${fu_cv_sys_stat_statfs3_osf1+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : fu_cv_sys_stat_statfs3_osf1=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include main () { struct statfs fsd; fsd.f_fsize = 0; exit (statfs (".", &fsd, sizeof (struct statfs))); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : fu_cv_sys_stat_statfs3_osf1=yes else fu_cv_sys_stat_statfs3_osf1=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi #C_MSG_RESULT($fu_cv_sys_stat_statfs3_osf1) if test $fu_cv_sys_stat_statfs3_osf1 = yes; then space=yes $as_echo "#define STAT_STATFS3_OSF1 1" >>confdefs.h fi fi if test $space = no; then # AIX { $as_echo "$as_me:${as_lineno-$LINENO}: checking for two-argument statfs with statfs.bsize member (AIX, 4.3BSD)" >&5 $as_echo_n "checking for two-argument statfs with statfs.bsize member (AIX, 4.3BSD)... " >&6; } if ${fu_cv_sys_stat_statfs2_bsize+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : fu_cv_sys_stat_statfs2_bsize=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_VFS_H #include #endif main () { struct statfs fsd; fsd.f_bsize = 0; exit (statfs (".", &fsd)); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : fu_cv_sys_stat_statfs2_bsize=yes else fu_cv_sys_stat_statfs2_bsize=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statfs2_bsize" >&5 $as_echo "$fu_cv_sys_stat_statfs2_bsize" >&6; } if test $fu_cv_sys_stat_statfs2_bsize = yes; then space=yes $as_echo "#define STAT_STATFS2_BSIZE 1" >>confdefs.h fi fi if test $space = no; then # SVR3 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for four-argument statfs (AIX-3.2.5, SVR3)" >&5 $as_echo_n "checking for four-argument statfs (AIX-3.2.5, SVR3)... " >&6; } if ${fu_cv_sys_stat_statfs4+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : fu_cv_sys_stat_statfs4=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include main () { struct statfs fsd; exit (statfs (".", &fsd, sizeof fsd, 0)); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : fu_cv_sys_stat_statfs4=yes else fu_cv_sys_stat_statfs4=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statfs4" >&5 $as_echo "$fu_cv_sys_stat_statfs4" >&6; } if test $fu_cv_sys_stat_statfs4 = yes; then space=yes $as_echo "#define STAT_STATFS4 1" >>confdefs.h fi fi if test $space = no; then # 4.4BSD and NetBSD { $as_echo "$as_me:${as_lineno-$LINENO}: checking for two-argument statfs with statfs.fsize member (4.4BSD and NetBSD)" >&5 $as_echo_n "checking for two-argument statfs with statfs.fsize member (4.4BSD and NetBSD)... " >&6; } if ${fu_cv_sys_stat_statfs2_fsize+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : fu_cv_sys_stat_statfs2_fsize=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif main () { struct statfs fsd; fsd.f_fsize = 0; exit (statfs (".", &fsd)); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : fu_cv_sys_stat_statfs2_fsize=yes else fu_cv_sys_stat_statfs2_fsize=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_statfs2_fsize" >&5 $as_echo "$fu_cv_sys_stat_statfs2_fsize" >&6; } if test $fu_cv_sys_stat_statfs2_fsize = yes; then space=yes $as_echo "#define STAT_STATFS2_FSIZE 1" >>confdefs.h fi fi if test $space = no; then # Ultrix { $as_echo "$as_me:${as_lineno-$LINENO}: checking for two-argument statfs with struct fs_data (Ultrix)" >&5 $as_echo_n "checking for two-argument statfs with struct fs_data (Ultrix)... " >&6; } if ${fu_cv_sys_stat_fs_data+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : fu_cv_sys_stat_fs_data=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_FS_TYPES_H #include #endif main () { struct fs_data fsd; /* Ultrix's statfs returns 1 for success, 0 for not mounted, -1 for failure. */ exit (statfs (".", &fsd) != 1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : fu_cv_sys_stat_fs_data=yes else fu_cv_sys_stat_fs_data=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $fu_cv_sys_stat_fs_data" >&5 $as_echo "$fu_cv_sys_stat_fs_data" >&6; } if test $fu_cv_sys_stat_fs_data = yes; then space=yes $as_echo "#define STAT_STATFS2_FS_DATA 1" >>confdefs.h fi fi statxfs_includes="\ $ac_includes_default #if HAVE_SYS_STATVFS_H # include #endif #if HAVE_SYS_VFS_H # include #endif #if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H # if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */ # include # include # elif HAVE_NETINET_IN_H && HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H /* Ultrix 4.4 needs these for the declaration of struct statfs. */ # include # include # include # endif #endif " ac_fn_c_check_member "$LINENO" "struct statfs" "f_namemax" "ac_cv_member_struct_statfs_f_namemax" "$statxfs_includes " if test "x$ac_cv_member_struct_statfs_f_namemax" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STATFS_F_NAMEMAX 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct statvfs" "f_namemax" "ac_cv_member_struct_statvfs_f_namemax" "$statxfs_includes " if test "x$ac_cv_member_struct_statvfs_f_namemax" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STATVFS_F_NAMEMAX 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct statfs" "f_namelen" "ac_cv_member_struct_statfs_f_namelen" "$statxfs_includes " if test "x$ac_cv_member_struct_statfs_f_namelen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STATFS_F_NAMELEN 1 _ACEOF fi ac_fn_c_check_member "$LINENO" "struct statvfs" "f_namelen" "ac_cv_member_struct_statvfs_f_namelen" "$statxfs_includes " if test "x$ac_cv_member_struct_statvfs_f_namelen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STATVFS_F_NAMELEN 1 _ACEOF fi # # Large file support # # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi # # mntent # ac_fn_c_check_header_mongrel "$LINENO" "mntent.h" "ac_cv_header_mntent_h" "$ac_includes_default" if test "x$ac_cv_header_mntent_h" = xyes; then : $as_echo "#define HAVE_MNTENT_H 1" >>confdefs.h fi for ac_func in setmntent do : ac_fn_c_check_func "$LINENO" "setmntent" "ac_cv_func_setmntent" if test "x$ac_cv_func_setmntent" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETMNTENT 1 _ACEOF fi done # # IPv6 # # Check whether --with-ipv6 was given. if test "${with_ipv6+set}" = set; then : withval=$with_ipv6; if test $withval != "no"; then $as_echo "#define IPv6 1" >>confdefs.h fi fi # # debugging # # Check whether --with-debug was given. if test "${with_debug+set}" = set; then : withval=$with_debug; if test $withval != "no"; then $as_echo "#define WITH_DEBUG 1" >>confdefs.h fi fi # Check whether --with-debug-kbd was given. if test "${with_debug_kbd+set}" = set; then : withval=$with_debug_kbd; if test $withval != "no"; then $as_echo "#define WITH_DEBUG_KBD 1" >>confdefs.h fi fi # Check whether --with-debug-rdp5 was given. if test "${with_debug_rdp5+set}" = set; then : withval=$with_debug_rdp5; if test $withval != "no"; then $as_echo "#define WITH_DEBUG_RDP5 1" >>confdefs.h fi fi # Check whether --with-debug-clipboard was given. if test "${with_debug_clipboard+set}" = set; then : withval=$with_debug_clipboard; if test $withval != "no"; then $as_echo "#define WITH_DEBUG_CLIPBOARD 1" >>confdefs.h fi fi # Check whether --with-debug-sound was given. if test "${with_debug_sound+set}" = set; then : withval=$with_debug_sound; if test $withval != "no"; then $as_echo "#define WITH_DEBUG_SOUND 1" >>confdefs.h fi fi # Check whether --with-debug-channel was given. if test "${with_debug_channel+set}" = set; then : withval=$with_debug_channel; if test $withval != "no"; then $as_echo "#define WITH_DEBUG_CHANNEL 1" >>confdefs.h fi fi # Check whether --with-debug-seamless was given. if test "${with_debug_seamless+set}" = set; then : withval=$with_debug_seamless; if test $withval != "no"; then $as_echo "#define WITH_DEBUG_SEAMLESS 1" >>confdefs.h fi fi # Check whether --with-debug-smartcard was given. if test "${with_debug_smartcard+set}" = set; then : withval=$with_debug_smartcard; if test $withval != "no"; then if test x"$WITH_SCARD" = "x1"; then $as_echo "#define WITH_DEBUG_SCARD 1" >>confdefs.h fi fi fi # Check whether --with-debug-credssp was given. if test "${with_debug_credssp+set}" = set; then : withval=$with_debug_credssp; if test $withval != "no"; then if test x"$WITH_CREDSSP" = "x1"; then $as_echo "#define WITH_DEBUG_CREDSSP 1" >>confdefs.h fi fi fi # # target-specific stuff # case "$host" in *-*-hpux*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED" ;; *-*-irix6.5*) LIBS="-L$ssldir/lib32 $LIBS" CFLAGS="$CFLAGS -D__SGI_IRIX__" ;; esac ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by rdesktop $as_me 1.8.3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ rdesktop config.status 1.8.3 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi rdesktop-1.8.3/configure.ac0000664000770100510440000006236612424672330014603 0ustar hean01hean01AC_INIT(rdesktop, 1.8.3) AC_CONFIG_SRCDIR([rdesktop.c]) AC_CANONICAL_HOST AC_PROG_CC if test "$GCC" = yes; then CFLAGS="$CFLAGS -Wall" fi AC_PROG_INSTALL AC_LANG_C AC_HEADER_STDC AC_C_BIGENDIAN([AC_DEFINE(B_ENDIAN)], [AC_DEFINE(L_ENDIAN)]) AC_PATH_XTRA if test "$no_x" = "yes"; then echo echo "ERROR: Could not find X Window System headers/libraries." if test -f /etc/debian_version; then echo "Probably you need to install the libx11-dev package." elif test -f /etc/redhat-release; then echo "Probably you need to install the libX11-devel package." fi echo "To specify paths manually, use the options --x-includes and --x-libraries." echo exit 1 fi AC_PATH_TOOL(PKG_CONFIG, pkg-config) AC_SEARCH_LIBS(socket, socket) AC_SEARCH_LIBS(inet_aton, resolv) AC_CHECK_HEADER(sys/select.h, AC_DEFINE(HAVE_SYS_SELECT_H)) AC_CHECK_HEADER(sys/modem.h, AC_DEFINE(HAVE_SYS_MODEM_H)) AC_CHECK_HEADER(sys/filio.h, AC_DEFINE(HAVE_SYS_FILIO_H)) AC_CHECK_HEADER(sys/strtio.h, AC_DEFINE(HAVE_SYS_STRTIO_H)) AC_CHECK_HEADER(locale.h, AC_DEFINE(HAVE_LOCALE_H)) AC_CHECK_HEADER(langinfo.h, AC_DEFINE(HAVE_LANGINFO_H)) AC_CHECK_HEADER(sysexits.h, AC_DEFINE(HAVE_SYSEXITS_H)) AC_CHECK_TOOL(STRIP, strip, :) dnl Don't depend on pkg-config m4_ifdef([PKG_CHECK_MODULES], [], [ m4_errprint([warning: pkg-config checks are not available]) m4_defun([PKG_CHECK_MODULES], [ AC_MSG_WARN([pkg-config not available, cannot check for $2]) $4 ]) ]) # # OpenSSL detection borrowed from stunnel # checkssldir() { : if test -f "$1/include/openssl/ssl.h"; then ssldir="$1" return 0 fi return 1 } AC_MSG_CHECKING([for OpenSSL directory]) AC_ARG_WITH(openssl, [ --with-openssl=DIR look for OpenSSL at DIR/include, DIR/lib], [ dnl Check the specified location only checkssldir "$withval" ], [ dnl Search default locations of OpenSSL library for maindir in /usr/local /usr/lib /usr/pkg /usr /var/ssl /opt; do for dir in $maindir $maindir/openssl $maindir/ssl; do checkssldir $dir && break 2 done done ] ) if test -z "$ssldir"; then AC_MSG_RESULT([Not found]) echo echo "ERROR: Could not find OpenSSL headers/libraries." if test -f /etc/debian_version; then echo "Probably you need to install the libssl-dev package." elif test -f /etc/redhat-release; then echo "Probably you need to install the openssl-devel package." fi echo "To specify a path manually, use the --with-openssl option." echo exit 1 fi AC_MSG_RESULT([$ssldir]) AC_SUBST(ssldir) AC_DEFINE_UNQUOTED(ssldir, "$ssldir") dnl Add OpenSSL includes and libraries CFLAGS="$CFLAGS -I$ssldir/include" AC_ARG_ENABLE(static-openssl, [ --enable-static-openssl link OpenSSL statically], [static_openssl=yes], [static_openssl=no]) if test x"$static_openssl" = "xyes"; then # OpenSSL generally relies on libz AC_SEARCH_LIBS(deflate, z) LIBS="-L$ssldir/lib -L$ssldir/lib64 -Wl,-Bstatic -lssl -lcrypto -Wl,-Bdynamic $LIBS" else LIBS="-L$ssldir/lib -L$ssldir/lib64 -lssl -lcrypto $LIBS" # # target-specific stuff # case "$host" in *-*-solaris*) LDFLAGS="$LDFLAGS -R$ssldir/lib" ;; *-dec-osf*) LDFLAGS="$LDFLAGS -Wl,-rpath,$ssldir/lib" ;; esac fi dnl CredSSP feature AC_ARG_ENABLE([credssp], AS_HELP_STRING([--disable-credssp], [disable support for CredSSP])) AC_ARG_ENABLE([static-gssglue], AS_HELP_STRING([--enable-static-gssglue]), [static_gssglue=yes], [static_gssglue=no]) AS_IF([test "x$enable_credssp" != "xno"], [ if test -n "$PKG_CONFIG"; then PKG_CHECK_MODULES(GSSGLUE, libgssglue, [WITH_CREDSSP=1], [WITH_CREDSSP=0]) fi if test x"$WITH_CREDSSP" = "x1"; then CREDSSPOBJ="cssp.o" CFLAGS="$CFLAGS $GSSGLUE_CFLAGS" AS_IF([test "x$static_gssglue" != "xno"], [ LIBS="$LIBS -Wl,-Bstatic -lgssglue -Wl,-Bdynamic" ], [ LIBS="$LIBS -lgssglue" ]) AC_DEFINE(WITH_CREDSSP) else echo echo "CredSSP support requires libgssglue, install the dependency" echo "or disable the feature using --disable-credssp." echo exit 1 fi ]) AC_SUBST(CREDSSPOBJ) # xrandr if test -n "$PKG_CONFIG"; then PKG_CHECK_MODULES(XRANDR, xrandr, [HAVE_XRANDR=1], [HAVE_XRANDR=0]) fi if test x"$HAVE_XRANDR" = "x1"; then CFLAGS="$CFLAGS $XRANDR_CFLAGS" LIBS="$LIBS $XRANDR_LIBS" AC_DEFINE(HAVE_XRANDR) fi dnl Smartcard support AC_ARG_ENABLE(smartcard, AS_HELP_STRING([--disable-smartcard], [disable support for smartcard])) AS_IF([test "x$enable_smartcard" != "xno"], [ case "$OSTYPE" in darwin*) AC_CHECK_HEADER(PCSC/pcsclite.h, [WITH_SCARD=1], [WITH_SCARD=0]) PCSCLITE_CFLAGS="" PCSCLITE_LIBS="-framework PCSC" ;; *) if test -n "$PKG_CONFIG"; then PKG_CHECK_MODULES(PCSCLITE, libpcsclite, [WITH_SCARD=1], [WITH_SCARD=0]) fi ;; esac if test x"$WITH_SCARD" = "x1"; then SCARDOBJ="scard.o" CFLAGS="$CFLAGS $PCSCLITE_CFLAGS" LIBS="$LIBS $PCSCLITE_LIBS" AC_DEFINE(WITH_SCARD) else echo echo "SmartCard support requires PCSC, install the dependency" echo "or disable the feature using --disable-smartcard." echo exit 1 fi AC_MSG_CHECKING([for old version of PCSC]) AC_TRY_LINK([ #include #ifdef __APPLE__ #include #include #else #include #endif ], [SCardControl(NULL, NULL, 0, NULL, NULL);], [AC_MSG_RESULT(yes) AC_DEFINE(WITH_PCSC120, 1, [old version of PCSC])], [AC_MSG_RESULT(no)]) ]) AC_SUBST(SCARDOBJ) # # Alignment # AC_MSG_CHECKING([if architecture needs alignment]) AC_TRY_RUN([ #include #include int main(int argc, char **argv) { unsigned char test[8] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; signal(SIGBUS, exit); signal(SIGABRT, exit); signal(SIGSEGV, exit); if (*((unsigned int *)(test + 1)) != 0x55443322 && *((unsigned int *)(test + 1)) != 0x22334455) { return 1; } return 0; }], [AC_MSG_RESULT(no)], [AC_MSG_RESULT(yes) AC_DEFINE(NEED_ALIGN)], [AC_MSG_RESULT(assuming yes) AC_DEFINE(NEED_ALIGN)]) # # EGD # AC_ARG_WITH(egd-socket, [ --with-egd-socket=PATH look for Entropy Gathering Daemon socket at PATH], [EGD_SOCKET="$withval"], [EGD_SOCKET="/var/run/egd-pool"] ) AC_DEFINE_UNQUOTED(EGD_SOCKET, "$EGD_SOCKET") # # rdp2vnc # vncserverconfig=libvncserver-config AC_ARG_WITH(libvncserver-config, [ --with-libvncserver-config=CMD use CMD as libvncserver-config], [vncserverconfig="$withval"] ) AC_ARG_WITH(libvncserver, [ --with-libvncserver make rdp2vnc], [ VNCINC=`$vncserverconfig --cflags` AC_SUBST(VNCINC) LDVNC=`$vncserverconfig --libs` AC_SUBST(LDVNC) VNCLINK=`$vncserverconfig --link` AC_SUBST(VNCLINK) RDP2VNCTARGET="rdp2vnc" AC_SUBST(RDP2VNCTARGET) ] ) # # sound # sound="yes" AC_ARG_WITH(sound, [ --with-sound select sound system ("oss", "sgi", "sun", "alsa" or "libao") ], [ sound="$withval" ]) AC_CHECK_HEADER(sys/soundcard.h, [HAVE_OSS=1], [HAVE_OSS=0]) AC_CHECK_HEADER(dmedia/audio.h, [HAVE_SGI=1], [HAVE_SGI=0]) AC_CHECK_HEADER(sys/audioio.h, [HAVE_SUN=1], [HAVE_SUN=0]) AC_ARG_ENABLE(static-libsamplerate, [ --enable-static-libsamplerate link libsamplerate statically], [static_libsamplerate=yes], [static_libsamplerate=no]) if test -n "$PKG_CONFIG"; then PKG_CHECK_MODULES(LIBAO, ao, [HAVE_LIBAO=1], [HAVE_LIBAO=0]) PKG_CHECK_MODULES(ALSA, alsa, [HAVE_ALSA=1], [HAVE_ALSA=0]) PKG_CHECK_MODULES(LIBSAMPLERATE, samplerate, [HAVE_LIBSAMPLERATE=1], [HAVE_LIBSAMPLERATE=0]) if test x"$HAVE_LIBSAMPLERATE" = "x1"; then AC_DEFINE(HAVE_LIBSAMPLERATE) if test x"$static_libsamplerate" = "xyes"; then _libsamplerate_libdir=`$PKG_CONFIG --errors-to-stdout --variable=libdir samplerate` LIBSAMPLERATE_LIBS="$_libsamplerate_libdir""/libsamplerate.a" LIBSAMPLERATE_LIBS="$LIBSAMPLERATE_LIBS -lm" fi fi fi if test "$sound" != "no"; then SOUNDOBJ="$SOUNDOBJ rdpsnd.o rdpsnd_dsp.o" CFLAGS="$CFLAGS $LIBSAMPLERATE_CFLAGS" LIBS="$LIBS $LIBSAMPLERATE_LIBS" AC_DEFINE(WITH_RDPSND) fi case $sound in yes) if test x"$HAVE_OSS" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_oss.o" AC_DEFINE(RDPSND_OSS) fi if test x"$HAVE_SGI" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_sgi.o" LIBS="$LIBS -laudio" AC_DEFINE(RDPSND_SGI) fi if test x"$HAVE_SUN" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_sun.o" AC_DEFINE(RDPSND_SUN) fi if test x"$HAVE_ALSA" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_alsa.o" CFLAGS="$CFLAGS $ALSA_CFLAGS" LIBS="$LIBS $ALSA_LIBS" AC_DEFINE(RDPSND_ALSA) fi if test x"$HAVE_LIBAO" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_libao.o" CFLAGS="$CFLAGS $LIBAO_CFLAGS" LIBS="$LIBS $LIBAO_LIBS" AC_DEFINE(RDPSND_LIBAO) fi ;; oss) if test x"$HAVE_OSS" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_oss.o" AC_DEFINE(RDPSND_OSS) else AC_MSG_ERROR([Selected sound system is not available.]) fi ;; sgi) if test x"$HAVE_SGI" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_sgi.o" LIBS="$LIBS -laudio" AC_DEFINE(RDPSND_SGI) else AC_MSG_ERROR([Selected sound system is not available.]) fi ;; sun) if test x"$HAVE_SUN" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_sun.o" AC_DEFINE(RDPSND_SUN) else AC_MSG_ERROR([Selected sound system is not available.]) fi ;; alsa) if test x"$HAVE_ALSA" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_alsa.o" CFLAGS="$CFLAGS $ALSA_CFLAGS" LIBS="$LIBS $ALSA_LIBS" AC_DEFINE(RDPSND_ALSA) else AC_MSG_ERROR([Selected sound system is not available.]) fi ;; libao) if test x"$HAVE_LIBAO" = "x1"; then SOUNDOBJ="$SOUNDOBJ rdpsnd_libao.o" CFLAGS="$CFLAGS $LIBAO_CFLAGS" LIBS="$LIBS $LIBAO_LIBS" AC_DEFINE(RDPSND_LIBAO) else AC_MSG_ERROR([Selected sound system is not available.]) fi ;; no) ;; *) AC_MSG_WARN([sound support disabled]) AC_MSG_WARN([Currently supported systems are Open Sound System (oss), SGI AL (sgi), Sun/BSD (sun), ALSA (alsa) and libao]) ;; esac AC_SUBST(SOUNDOBJ) # # dirfd # dnl Find out how to get the file descriptor associated with an open DIR*. dnl From Jim Meyering AC_DEFUN([UTILS_FUNC_DIRFD], [ AC_HEADER_DIRENT dirfd_headers=' #if HAVE_DIRENT_H # include #else /* not HAVE_DIRENT_H */ # define dirent direct # if HAVE_SYS_NDIR_H # include # endif /* HAVE_SYS_NDIR_H */ # if HAVE_SYS_DIR_H # include # endif /* HAVE_SYS_DIR_H */ # if HAVE_NDIR_H # include # endif /* HAVE_NDIR_H */ #endif /* HAVE_DIRENT_H */ ' AC_CHECK_FUNCS(dirfd) AC_CHECK_DECLS([dirfd], , , $dirfd_headers) AC_CACHE_CHECK([whether dirfd is a macro], jm_cv_func_dirfd_macro, [AC_EGREP_CPP([dirent_header_defines_dirfd], [$dirfd_headers #ifdef dirfd dirent_header_defines_dirfd #endif], jm_cv_func_dirfd_macro=yes, jm_cv_func_dirfd_macro=no)]) # Use the replacement only if we have no function, macro, # or declaration with that name. if test $ac_cv_func_dirfd,$ac_cv_have_decl_dirfd,$jm_cv_func_dirfd_macro \ = no,no,no; then AC_REPLACE_FUNCS([dirfd]) AC_CACHE_CHECK( [how to get the file descriptor associated with an open DIR*], gl_cv_sys_dir_fd_member_name, [ dirfd_save_CFLAGS=$CFLAGS for ac_expr in d_fd dd_fd; do CFLAGS="$CFLAGS -DDIR_FD_MEMBER_NAME=$ac_expr" AC_TRY_COMPILE( [$dirfd_headers ], [DIR *dir_p = opendir("."); (void) dir_p->DIR_FD_MEMBER_NAME;], dir_fd_found=yes ) CFLAGS=$dirfd_save_CFLAGS test "$dir_fd_found" = yes && break done test "$dir_fd_found" = yes || ac_expr=no_such_member gl_cv_sys_dir_fd_member_name=$ac_expr ] ) if test $gl_cv_sys_dir_fd_member_name != no_such_member; then AC_DEFINE_UNQUOTED(DIR_FD_MEMBER_NAME, $gl_cv_sys_dir_fd_member_name, [the name of the file descriptor member of DIR]) fi AH_VERBATIM(DIR_TO_FD, [#ifdef DIR_FD_MEMBER_NAME # define DIR_TO_FD(Dir_p) ((Dir_p)->DIR_FD_MEMBER_NAME) #else # define DIR_TO_FD(Dir_p) -1 #endif ] ) fi ]) UTILS_FUNC_DIRFD # # iconv # dnl This macros shamelessly stolen from dnl http://gcc.gnu.org/ml/gcc-bugs/2001-06/msg01398.html. dnl Written by Bruno Haible. AC_DEFUN([UTILS_FUNC_ICONV], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). AC_ARG_WITH([libiconv-prefix], [ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [ for dir in `echo "$withval" | tr : ' '`; do if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi done ]) AC_CHECK_HEADER(iconv.h, AC_DEFINE(HAVE_ICONV_H)) AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_func_iconv=yes) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS -liconv" AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_lib_iconv=yes am_cv_func_iconv=yes) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_TRY_COMPILE([ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, [Define as const if the declaration of iconv() needs const.]) fi LIBICONV= if test "$am_cv_lib_iconv" = yes; then LIBICONV="-liconv" fi AC_SUBST(LIBICONV) ]) UTILS_FUNC_ICONV LIBS="$LIBS $LIBICONV" # # socklen_t # from curl dnl Check for socklen_t: historically on BSD it is an int, and in dnl POSIX 1g it is a type of its own, but some platforms use different dnl types for the argument to getsockopt, getpeername, etc. So we dnl have to test to find something that will work. AC_DEFUN([TYPE_SOCKLEN_T], [ AC_CHECK_TYPE([socklen_t], ,[ AC_MSG_CHECKING([for socklen_t equivalent]) AC_CACHE_VAL([socklen_t_cv_equiv], [ # Systems have either "struct sockaddr *" or # "void *" as the second argument to getpeername socklen_t_cv_equiv= for arg2 in "struct sockaddr" void; do for t in int size_t unsigned long "unsigned long"; do AC_TRY_COMPILE([ #include #include int getpeername (int, $arg2 *, $t *); ],[ $t len; getpeername(0,0,&len); ],[ socklen_t_cv_equiv="$t" break ]) done done if test "x$socklen_t_cv_equiv" = x; then AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) fi ]) AC_MSG_RESULT($socklen_t_cv_equiv) AC_DEFINE_UNQUOTED(socklen_t, $socklen_t_cv_equiv, [type to use in place of socklen_t if not defined])], [#include #include ]) ]) TYPE_SOCKLEN_T # # statfs stuff # AC_CHECK_HEADERS(sys/vfs.h) AC_CHECK_HEADERS(sys/statvfs.h) AC_CHECK_HEADERS(sys/statfs.h) AC_CHECK_HEADERS(sys/param.h) mount_includes="\ $ac_includes_default #if HAVE_SYS_PARAM_H # include #endif " AC_CHECK_HEADERS(sys/mount.h,,,[$mount_includes]) ################################################# # these tests are taken from the GNU fileutils package AC_CHECKING(how to get filesystem space usage) space=no # Test for statvfs64. if test $space = no; then # SVR4 AC_CACHE_CHECK([statvfs64 function (SVR4)], fu_cv_sys_stat_statvfs64, [AC_TRY_RUN([ #if defined(HAVE_UNISTD_H) #include #endif #include #include main () { struct statvfs64 fsd; exit (statvfs64 (".", &fsd)); }], fu_cv_sys_stat_statvfs64=yes, fu_cv_sys_stat_statvfs64=no, fu_cv_sys_stat_statvfs64=cross)]) if test $fu_cv_sys_stat_statvfs64 = yes; then space=yes AC_DEFINE(STAT_STATVFS64,1,[Whether statvfs64() is available]) fi fi # Perform only the link test since it seems there are no variants of the # statvfs function. This check is more than just AC_CHECK_FUNCS(statvfs) # because that got a false positive on SCO OSR5. Adding the declaration # of a `struct statvfs' causes this test to fail (as it should) on such # systems. That system is reported to work fine with STAT_STATFS4 which # is what it gets when this test fails. if test $space = no; then # SVR4 AC_CACHE_CHECK([statvfs function (SVR4)], fu_cv_sys_stat_statvfs, [AC_TRY_LINK([#include #include ], [struct statvfs fsd; statvfs (0, &fsd);], fu_cv_sys_stat_statvfs=yes, fu_cv_sys_stat_statvfs=no)]) if test $fu_cv_sys_stat_statvfs = yes; then space=yes AC_DEFINE(STAT_STATVFS,1,[Whether statvfs() is available]) fi fi if test $space = no; then # DEC Alpha running OSF/1 AC_MSG_CHECKING([for 3-argument statfs function (DEC OSF/1)]) AC_CACHE_VAL(fu_cv_sys_stat_statfs3_osf1, [AC_TRY_RUN([ #include #include #include main () { struct statfs fsd; fsd.f_fsize = 0; exit (statfs (".", &fsd, sizeof (struct statfs))); }], fu_cv_sys_stat_statfs3_osf1=yes, fu_cv_sys_stat_statfs3_osf1=no, fu_cv_sys_stat_statfs3_osf1=no)]) #C_MSG_RESULT($fu_cv_sys_stat_statfs3_osf1) if test $fu_cv_sys_stat_statfs3_osf1 = yes; then space=yes AC_DEFINE(STAT_STATFS3_OSF1,1,[Whether statfs requires 3 arguments]) fi fi if test $space = no; then # AIX AC_MSG_CHECKING([for two-argument statfs with statfs.bsize dnl member (AIX, 4.3BSD)]) AC_CACHE_VAL(fu_cv_sys_stat_statfs2_bsize, [AC_TRY_RUN([ #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_VFS_H #include #endif main () { struct statfs fsd; fsd.f_bsize = 0; exit (statfs (".", &fsd)); }], fu_cv_sys_stat_statfs2_bsize=yes, fu_cv_sys_stat_statfs2_bsize=no, fu_cv_sys_stat_statfs2_bsize=no)]) AC_MSG_RESULT($fu_cv_sys_stat_statfs2_bsize) if test $fu_cv_sys_stat_statfs2_bsize = yes; then space=yes AC_DEFINE(STAT_STATFS2_BSIZE,1,[Whether statfs requires two arguments and struct statfs has bsize property]) fi fi if test $space = no; then # SVR3 AC_MSG_CHECKING([for four-argument statfs (AIX-3.2.5, SVR3)]) AC_CACHE_VAL(fu_cv_sys_stat_statfs4, [AC_TRY_RUN([#include #include main () { struct statfs fsd; exit (statfs (".", &fsd, sizeof fsd, 0)); }], fu_cv_sys_stat_statfs4=yes, fu_cv_sys_stat_statfs4=no, fu_cv_sys_stat_statfs4=no)]) AC_MSG_RESULT($fu_cv_sys_stat_statfs4) if test $fu_cv_sys_stat_statfs4 = yes; then space=yes AC_DEFINE(STAT_STATFS4,1,[Whether statfs requires 4 arguments]) fi fi if test $space = no; then # 4.4BSD and NetBSD AC_MSG_CHECKING([for two-argument statfs with statfs.fsize dnl member (4.4BSD and NetBSD)]) AC_CACHE_VAL(fu_cv_sys_stat_statfs2_fsize, [AC_TRY_RUN([#include #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif main () { struct statfs fsd; fsd.f_fsize = 0; exit (statfs (".", &fsd)); }], fu_cv_sys_stat_statfs2_fsize=yes, fu_cv_sys_stat_statfs2_fsize=no, fu_cv_sys_stat_statfs2_fsize=no)]) AC_MSG_RESULT($fu_cv_sys_stat_statfs2_fsize) if test $fu_cv_sys_stat_statfs2_fsize = yes; then space=yes AC_DEFINE(STAT_STATFS2_FSIZE,1,[Whether statfs requires 2 arguments and struct statfs has fsize]) fi fi if test $space = no; then # Ultrix AC_MSG_CHECKING([for two-argument statfs with struct fs_data (Ultrix)]) AC_CACHE_VAL(fu_cv_sys_stat_fs_data, [AC_TRY_RUN([#include #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_FS_TYPES_H #include #endif main () { struct fs_data fsd; /* Ultrix's statfs returns 1 for success, 0 for not mounted, -1 for failure. */ exit (statfs (".", &fsd) != 1); }], fu_cv_sys_stat_fs_data=yes, fu_cv_sys_stat_fs_data=no, fu_cv_sys_stat_fs_data=no)]) AC_MSG_RESULT($fu_cv_sys_stat_fs_data) if test $fu_cv_sys_stat_fs_data = yes; then space=yes AC_DEFINE(STAT_STATFS2_FS_DATA,1,[Whether statfs requires 2 arguments and struct fs_data is available]) fi fi statxfs_includes="\ $ac_includes_default #if HAVE_SYS_STATVFS_H # include #endif #if HAVE_SYS_VFS_H # include #endif #if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H # if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */ # include # include # elif HAVE_NETINET_IN_H && HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H /* Ultrix 4.4 needs these for the declaration of struct statfs. */ # include # include # include # endif #endif " AC_CHECK_MEMBERS([struct statfs.f_namemax],,,[$statxfs_includes]) AC_CHECK_MEMBERS([struct statvfs.f_namemax],,,[$statxfs_includes]) AC_CHECK_MEMBERS([struct statfs.f_namelen],,,[$statxfs_includes]) AC_CHECK_MEMBERS([struct statvfs.f_namelen],,,[$statxfs_includes]) # # Large file support # AC_SYS_LARGEFILE # # mntent # AC_CHECK_HEADER(mntent.h, AC_DEFINE(HAVE_MNTENT_H)) AC_CHECK_FUNCS(setmntent) # # IPv6 # AC_ARG_WITH(ipv6, [ --with-ipv6 enable IPv6-support], [ if test $withval != "no"; then AC_DEFINE(IPv6,1) fi ]) # # debugging # AC_ARG_WITH(debug, [ --with-debug enable protocol debugging output], [ if test $withval != "no"; then AC_DEFINE(WITH_DEBUG,1) fi ]) AC_ARG_WITH(debug-kbd, [ --with-debug-kbd enable debugging of keyboard handling], [ if test $withval != "no"; then AC_DEFINE(WITH_DEBUG_KBD,1) fi ]) AC_ARG_WITH(debug-rdp5, [ --with-debug-rdp5 enable debugging of RDP5 code], [ if test $withval != "no"; then AC_DEFINE(WITH_DEBUG_RDP5,1) fi ]) AC_ARG_WITH(debug-clipboard, [ --with-debug-clipboard enable debugging of clipboard code], [ if test $withval != "no"; then AC_DEFINE(WITH_DEBUG_CLIPBOARD,1) fi ]) AC_ARG_WITH(debug-sound, [ --with-debug-sound enable debugging of sound code], [ if test $withval != "no"; then AC_DEFINE(WITH_DEBUG_SOUND,1) fi ]) AC_ARG_WITH(debug-channel, [ --with-debug-channel enable debugging of virtual channel code], [ if test $withval != "no"; then AC_DEFINE(WITH_DEBUG_CHANNEL,1) fi ]) AC_ARG_WITH(debug-seamless, [ --with-debug-seamless enable debugging of SeamlessRDP code], [ if test $withval != "no"; then AC_DEFINE(WITH_DEBUG_SEAMLESS,1) fi ]) AC_ARG_WITH(debug-smartcard, [ --with-debug-smartcard enable debugging of smart-card code], [ if test $withval != "no"; then if test x"$WITH_SCARD" = "x1"; then AC_DEFINE(WITH_DEBUG_SCARD,1) fi fi ]) AC_ARG_WITH(debug-credssp, [ --with-debug-credssp enable debugging of CredSSP code], [ if test $withval != "no"; then if test x"$WITH_CREDSSP" = "x1"; then AC_DEFINE(WITH_DEBUG_CREDSSP,1) fi fi ]) # # target-specific stuff # case "$host" in *-*-hpux*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED" ;; *-*-irix6.5*) LIBS="-L$ssldir/lib32 $LIBS" CFLAGS="$CFLAGS -D__SGI_IRIX__" ;; esac AC_OUTPUT(Makefile) dnl Local Variables: dnl comment-start: "dnl " dnl comment-end: "" dnl comment-start-skip: "\\bdnl\\b\\s *" dnl compile-command: "autoconf" dnl End: rdesktop-1.8.3/config.sub0000775000770100510440000007301510102714635014265 0ustar hean01hean01#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-06-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | s390 | s390x \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | msp430-* \ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | s390-* | s390x-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nv1) basic_machine=nv1-cray os=-unicosmp ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rdesktop-1.8.3/config.guess0000775000770100510440000012206510102714635014622 0ustar hean01hean01#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-06-17' # This file 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. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown ## for Red Hat Linux if test -f /etc/redhat-release ; then VENDOR=redhat ; else VENDOR= ; fi # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha*:OpenVMS:*:*) echo alpha-hp-vms exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*|*:GNU/FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #if __GLIBC__ >= 2 LIBC=gnu #else LIBC= #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-${VENDOR:-unknown}-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-${VENDOR:-unknown}-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-${VENDOR:-unknown}-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-${VENDOR:-unknown}-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR:-pc}-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) case `uname -p` in *86) UNAME_PROCESSOR=i686 ;; powerpc) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rdesktop-1.8.3/bootstrap0000775000770100510440000000005610117316232014235 0ustar hean01hean01#!/bin/sh rm -rf autom4te.cache autoreconf -i rdesktop-1.8.3/install-sh0000775000770100510440000001270110102714635014301 0ustar hean01hean01#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else : fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f "$src" ] || [ -d "$src" ] then : else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else : fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else : fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else : fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else : fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 rdesktop-1.8.3/Makefile.in0000664000770100510440000001177212077232136014355 0ustar hean01hean01# # rdesktop: A Remote Desktop Protocol client # Makefile.in # Copyright (C) Matthew Chapman 1999-2007 # prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ mandir = @mandir@ datarootdir = @datarootdir@ datadir = @datadir@ VERSION = @PACKAGE_VERSION@ KEYMAP_PATH = $(datadir)/rdesktop/keymaps/ CC = @CC@ INSTALL = @INSTALL@ CFLAGS = @CFLAGS@ @X_CFLAGS@ @DEFS@ -DKEYMAP_PATH=\"$(KEYMAP_PATH)\" LDFLAGS = @LDFLAGS@ @LIBS@ @X_LIBS@ @X_EXTRA_LIBS@ STRIP = @STRIP@ TARGETS = rdesktop @RDP2VNCTARGET@ VNCINC = @VNCINC@ LDVNC = @LDVNC@ VNCLINK = @VNCLINK@ SOUNDOBJ = @SOUNDOBJ@ SCARDOBJ = @SCARDOBJ@ CREDSSPOBJ = @CREDSSPOBJ@ RDPOBJ = tcp.o asn.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o lspci.o seamless.o ssl.o utils.o X11OBJ = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o ctrl.o VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o .PHONY: all all: $(TARGETS) rdesktop: $(X11OBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(CREDSSPOBJ) $(CC) $(CFLAGS) -o rdesktop $(X11OBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(CREDSSPOBJ) $(LDFLAGS) -lX11 rdp2vnc: $(VNCOBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(CREDSSPOBJ) $(VNCLINK) $(CFLAGS) -o rdp2vnc $(VNCOBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(CREDSSPOBJ) $(LDFLAGS) $(LDVNC) vnc/rdp2vnc.o: rdesktop.c $(CC) $(CFLAGS) $(VNCINC) -DRDP2VNC -o vnc/rdp2vnc.o -c rdesktop.c vnc/vnc.o: vnc/vnc.c $(CC) $(CFLAGS) $(VNCINC) -DRDP2VNC -o vnc/vnc.o -c vnc/vnc.c vnc/xkeymap.o: xkeymap.c $(CC) $(CFLAGS) $(VNCINC) -DRDP2VNC -o vnc/xkeymap.o -c xkeymap.c vnc/x11stubs.o: vnc/x11stubs.c $(CC) $(CFLAGS) $(VNCINC) -o vnc/x11stubs.o -c vnc/x11stubs.c .PHONY: install install: installbin installkeymaps installman .PHONY: installbin installbin: rdesktop mkdir -p $(DESTDIR)$(bindir) $(INSTALL) rdesktop $(DESTDIR)$(bindir) $(STRIP) $(DESTDIR)$(bindir)/rdesktop chmod 755 $(DESTDIR)$(bindir)/rdesktop .PHONY: installman installman: doc/rdesktop.1 mkdir -p $(DESTDIR)$(mandir)/man1 cp doc/rdesktop.1 $(DESTDIR)$(mandir)/man1 chmod 644 $(DESTDIR)$(mandir)/man1/rdesktop.1 .PHONY: installkeymaps installkeymaps: mkdir -p $(DESTDIR)$(KEYMAP_PATH) # Prevent copying the CVS directory cp keymaps/?? keymaps/??-?? $(DESTDIR)$(KEYMAP_PATH) cp keymaps/common $(DESTDIR)$(KEYMAP_PATH) cp keymaps/modifiers $(DESTDIR)$(KEYMAP_PATH) chmod 644 $(DESTDIR)$(KEYMAP_PATH)/* .PHONY: proto proto: cat proto.head > proto.h cproto -DMAKE_PROTO \ bitmap.c cache.c channels.c cliprdr.c disk.c mppc.c ewmhints.c \ iso.c licence.c mcs.c orders.c parallel.c printer.c printercache.c \ pstcache.c rdesktop.c rdp5.c rdp.c rdpdr.c rdpsnd.c \ secure.c serial.c tcp.c xclip.c xkeymap.c xwin.c lspci.c seamless.c \ scard.c >> proto.h cat proto.tail >> proto.h .PHONY: clean clean: rm -f *.o *~ vnc/*.o vnc/*~ rdesktop rdp2vnc .PHONY: distclean distclean: clean rm -rf autom4te.cache config.log config.status Makefile rdesktop-$(VERSION).tar.gz .PHONY: dist dist: rdesktop-$(VERSION).tar.gz rdesktop-$(VERSION).tar.gz: Makefile configure mkdir -p /tmp/rdesktop-make-dist-dir ln -sf `pwd` /tmp/rdesktop-make-dist-dir/rdesktop-$(VERSION) (cd /tmp/rdesktop-make-dist-dir; \ tar zcvf rdesktop-$(VERSION)/rdesktop-$(VERSION).tar.gz \ rdesktop-$(VERSION)/COPYING \ rdesktop-$(VERSION)/README \ rdesktop-$(VERSION)/configure \ rdesktop-$(VERSION)/configure.ac \ rdesktop-$(VERSION)/config.sub \ rdesktop-$(VERSION)/config.guess \ rdesktop-$(VERSION)/bootstrap \ rdesktop-$(VERSION)/install-sh \ rdesktop-$(VERSION)/Makefile.in \ rdesktop-$(VERSION)/rdesktop.spec \ rdesktop-$(VERSION)/*.c \ rdesktop-$(VERSION)/*.h \ rdesktop-$(VERSION)/proto.head \ rdesktop-$(VERSION)/proto.tail \ rdesktop-$(VERSION)/keymaps/?? \ rdesktop-$(VERSION)/keymaps/??-?? \ rdesktop-$(VERSION)/keymaps/common \ rdesktop-$(VERSION)/keymaps/modifiers \ rdesktop-$(VERSION)/keymaps/convert-map \ rdesktop-$(VERSION)/doc/HACKING \ rdesktop-$(VERSION)/doc/AUTHORS \ rdesktop-$(VERSION)/doc/TODO \ rdesktop-$(VERSION)/doc/ChangeLog \ rdesktop-$(VERSION)/doc/keymapping.txt \ rdesktop-$(VERSION)/doc/keymap-names.txt \ rdesktop-$(VERSION)/doc/ipv6.txt \ rdesktop-$(VERSION)/doc/licensing.txt \ rdesktop-$(VERSION)/doc/patches.txt \ rdesktop-$(VERSION)/doc/redirection.txt \ rdesktop-$(VERSION)/doc/rdesktop.1 ) rm -rf /tmp/rdesktop-make-dist-dir .PHONY: dist-noversion dist-noversion: rdesktop.tar.gz rdesktop.tar.gz: rdesktop-$(VERSION).tar.gz mkdir -p /tmp/rdesktop-make-dist-dir tar zxvf $< -C /tmp/rdesktop-make-dist-dir mv /tmp/rdesktop-make-dist-dir/rdesktop-$(VERSION) /tmp/rdesktop-make-dist-dir/rdesktop ls /tmp/rdesktop-make-dist-dir/rdesktop tar zcvf $@ -C /tmp/rdesktop-make-dist-dir rdesktop rm -rf /tmp/rdesktop-make-dist-dir Makefile: Makefile.in configure ./config.status configure: configure.ac ./bootstrap .SUFFIXES: .SUFFIXES: .c .o .c.o: $(CC) $(CFLAGS) -o $@ -c $< .PHONY: doc/AUTHORS doc/AUTHORS: ./genauthors *.c rdesktop-1.8.3/rdesktop.spec0000664000770100510440000000156412424672330015015 0ustar hean01hean01Summary: Remote Desktop Protocol client Name: rdesktop Version: 1.8.3 Release: 1 License: GPL; see COPYING Group: Applications/Communications Source: rdesktop-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-buildroot Packager: Peter Åstrand %description rdesktop is a client for Remote Desktop Protocol (RDP), used in a number of Microsoft products including Windows NT Terminal Server, Windows 2000 Server, Windows XP, Windows 2003 Server and Windows 2008r2. %prep rm -rf $RPM_BUILD_ROOT %setup %build ./configure --prefix=%{_prefix} --bindir=%{_bindir} --mandir=%{_mandir} make %install make install DESTDIR=$RPM_BUILD_ROOT %files %defattr(-,root,root) %doc COPYING doc/AUTHORS doc/keymapping.txt doc/keymap-names.txt doc/ipv6.txt doc/ChangeLog %{_bindir}/rdesktop %{_mandir}/man1/rdesktop.1* %{_datadir}/rdesktop/keymaps %clean rm -rf $RPM_BUILD_ROOT rdesktop-1.8.3/asn.c0000664000770100510440000000402712051535600013222 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. ASN.1 utility functions Copyright 2012 Henrik Andersson for Cendio AB 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 3 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, see . */ #include "rdesktop.h" /* Parse an ASN.1 BER header */ RD_BOOL ber_parse_header(STREAM s, int tagval, int *length) { int tag, len; if (tagval > 0xff) { in_uint16_be(s, tag); } else { in_uint8(s, tag); } if (tag != tagval) { error("expected tag %d, got %d\n", tagval, tag); return False; } in_uint8(s, len); if (len & 0x80) { len &= ~0x80; *length = 0; while (len--) next_be(s, *length); } else *length = len; return s_check(s); } /* Output an ASN.1 BER header */ void ber_out_header(STREAM s, int tagval, int length) { if (tagval > 0xff) { out_uint16_be(s, tagval); } else { out_uint8(s, tagval); } if (length >= 0x80) { out_uint8(s, 0x82); out_uint16_be(s, length); } else out_uint8(s, length); } /* Output an ASN.1 BER integer */ void ber_out_integer(STREAM s, int value) { ber_out_header(s, BER_TAG_INTEGER, 2); out_uint16_be(s, value); } RD_BOOL ber_in_header(STREAM s, int *tagval, int *decoded_len) { in_uint8(s, *tagval); in_uint8(s, *decoded_len); if (*decoded_len < 0x80) return True; else if (*decoded_len == 0x81) { in_uint8(s, *decoded_len); return True; } else if (*decoded_len == 0x82) { in_uint16_be(s, *decoded_len); return True; } return False; } rdesktop-1.8.3/bitmap.c0000664000770100510440000004263611551302500013720 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Bitmap decompression routines Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ /* three seperate function for speed when decompressing the bitmaps when modifing one function make the change in the others jay.sorg@gmail.com */ /* indent is confused by this file */ /* *INDENT-OFF* */ #include "rdesktop.h" #define CVAL(p) (*(p++)) #ifdef NEED_ALIGN #ifdef L_ENDIAN #define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; } #else #define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); } #endif /* L_ENDIAN */ #else #define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; } #endif /* NEED_ALIGN */ #define UNROLL8(exp) { exp exp exp exp exp exp exp exp } #define REPEAT(statement) \ { \ while((count & ~0x7) && ((x+8) < width)) \ UNROLL8( statement; count--; x++; ); \ \ while((count > 0) && (x < width)) \ { \ statement; \ count--; \ x++; \ } \ } #define MASK_UPDATE() \ { \ mixmask <<= 1; \ if (mixmask == 0) \ { \ mask = fom_mask ? fom_mask : CVAL(input); \ mixmask = 1; \ } \ } /* 1 byte bitmap decompress */ static RD_BOOL bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size) { uint8 *end = input + size; uint8 *prevline = NULL, *line = NULL; int opcode, count, offset, isfillormix, x = width; int lastopcode = -1, insertmix = False, bicolour = False; uint8 code; uint8 colour1 = 0, colour2 = 0; uint8 mixmask, mask = 0; uint8 mix = 0xff; int fom_mask = 0; while (input < end) { fom_mask = 0; code = CVAL(input); opcode = code >> 4; /* Handle different opcode forms */ switch (opcode) { case 0xc: case 0xd: case 0xe: opcode -= 6; count = code & 0xf; offset = 16; break; case 0xf: opcode = code & 0xf; if (opcode < 9) { count = CVAL(input); count |= CVAL(input) << 8; } else { count = (opcode < 0xb) ? 8 : 1; } offset = 0; break; default: opcode >>= 1; count = code & 0x1f; offset = 32; break; } /* Handle strange cases for counts */ if (offset != 0) { isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) { if (isfillormix) count = CVAL(input) + 1; else count = CVAL(input) + offset; } else if (isfillormix) { count <<= 3; } } /* Read preliminary data */ switch (opcode) { case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (prevline == NULL))) insertmix = True; break; case 8: /* Bicolour */ colour1 = CVAL(input); case 3: /* Colour */ colour2 = CVAL(input); break; case 6: /* SetMix/Mix */ case 7: /* SetMix/FillOrMix */ mix = CVAL(input); opcode -= 5; break; case 9: /* FillOrMix_1 */ mask = 0x03; opcode = 0x02; fom_mask = 3; break; case 0x0a: /* FillOrMix_2 */ mask = 0x05; opcode = 0x02; fom_mask = 5; break; } lastopcode = opcode; mixmask = 0; /* Output body */ while (count > 0) { if (x >= width) { if (height <= 0) return False; x = 0; height--; prevline = line; line = output + height * width; } switch (opcode) { case 0: /* Fill */ if (insertmix) { if (prevline == NULL) line[x] = mix; else line[x] = prevline[x] ^ mix; insertmix = False; count--; x++; } if (prevline == NULL) { REPEAT(line[x] = 0) } else { REPEAT(line[x] = prevline[x]) } break; case 1: /* Mix */ if (prevline == NULL) { REPEAT(line[x] = mix) } else { REPEAT(line[x] = prevline[x] ^ mix) } break; case 2: /* Fill or Mix */ if (prevline == NULL) { REPEAT ( MASK_UPDATE(); if (mask & mixmask) line[x] = mix; else line[x] = 0; ) } else { REPEAT ( MASK_UPDATE(); if (mask & mixmask) line[x] = prevline[x] ^ mix; else line[x] = prevline[x]; ) } break; case 3: /* Colour */ REPEAT(line[x] = colour2) break; case 4: /* Copy */ REPEAT(line[x] = CVAL(input)) break; case 8: /* Bicolour */ REPEAT ( if (bicolour) { line[x] = colour2; bicolour = False; } else { line[x] = colour1; bicolour = True; count++; } ) break; case 0xd: /* White */ REPEAT(line[x] = 0xff) break; case 0xe: /* Black */ REPEAT(line[x] = 0) break; default: unimpl("bitmap opcode 0x%x\n", opcode); return False; } } } return True; } /* 2 byte bitmap decompress */ static RD_BOOL bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size) { uint8 *end = input + size; uint16 *prevline = NULL, *line = NULL; int opcode, count, offset, isfillormix, x = width; int lastopcode = -1, insertmix = False, bicolour = False; uint8 code; uint16 colour1 = 0, colour2 = 0; uint8 mixmask, mask = 0; uint16 mix = 0xffff; int fom_mask = 0; while (input < end) { fom_mask = 0; code = CVAL(input); opcode = code >> 4; /* Handle different opcode forms */ switch (opcode) { case 0xc: case 0xd: case 0xe: opcode -= 6; count = code & 0xf; offset = 16; break; case 0xf: opcode = code & 0xf; if (opcode < 9) { count = CVAL(input); count |= CVAL(input) << 8; } else { count = (opcode < 0xb) ? 8 : 1; } offset = 0; break; default: opcode >>= 1; count = code & 0x1f; offset = 32; break; } /* Handle strange cases for counts */ if (offset != 0) { isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) { if (isfillormix) count = CVAL(input) + 1; else count = CVAL(input) + offset; } else if (isfillormix) { count <<= 3; } } /* Read preliminary data */ switch (opcode) { case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (prevline == NULL))) insertmix = True; break; case 8: /* Bicolour */ CVAL2(input, colour1); case 3: /* Colour */ CVAL2(input, colour2); break; case 6: /* SetMix/Mix */ case 7: /* SetMix/FillOrMix */ CVAL2(input, mix); opcode -= 5; break; case 9: /* FillOrMix_1 */ mask = 0x03; opcode = 0x02; fom_mask = 3; break; case 0x0a: /* FillOrMix_2 */ mask = 0x05; opcode = 0x02; fom_mask = 5; break; } lastopcode = opcode; mixmask = 0; /* Output body */ while (count > 0) { if (x >= width) { if (height <= 0) return False; x = 0; height--; prevline = line; line = ((uint16 *) output) + height * width; } switch (opcode) { case 0: /* Fill */ if (insertmix) { if (prevline == NULL) line[x] = mix; else line[x] = prevline[x] ^ mix; insertmix = False; count--; x++; } if (prevline == NULL) { REPEAT(line[x] = 0) } else { REPEAT(line[x] = prevline[x]) } break; case 1: /* Mix */ if (prevline == NULL) { REPEAT(line[x] = mix) } else { REPEAT(line[x] = prevline[x] ^ mix) } break; case 2: /* Fill or Mix */ if (prevline == NULL) { REPEAT ( MASK_UPDATE(); if (mask & mixmask) line[x] = mix; else line[x] = 0; ) } else { REPEAT ( MASK_UPDATE(); if (mask & mixmask) line[x] = prevline[x] ^ mix; else line[x] = prevline[x]; ) } break; case 3: /* Colour */ REPEAT(line[x] = colour2) break; case 4: /* Copy */ REPEAT(CVAL2(input, line[x])) break; case 8: /* Bicolour */ REPEAT ( if (bicolour) { line[x] = colour2; bicolour = False; } else { line[x] = colour1; bicolour = True; count++; } ) break; case 0xd: /* White */ REPEAT(line[x] = 0xffff) break; case 0xe: /* Black */ REPEAT(line[x] = 0) break; default: unimpl("bitmap opcode 0x%x\n", opcode); return False; } } } return True; } /* 3 byte bitmap decompress */ static RD_BOOL bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size) { uint8 *end = input + size; uint8 *prevline = NULL, *line = NULL; int opcode, count, offset, isfillormix, x = width; int lastopcode = -1, insertmix = False, bicolour = False; uint8 code; uint8 colour1[3] = {0, 0, 0}, colour2[3] = {0, 0, 0}; uint8 mixmask, mask = 0; uint8 mix[3] = {0xff, 0xff, 0xff}; int fom_mask = 0; while (input < end) { fom_mask = 0; code = CVAL(input); opcode = code >> 4; /* Handle different opcode forms */ switch (opcode) { case 0xc: case 0xd: case 0xe: opcode -= 6; count = code & 0xf; offset = 16; break; case 0xf: opcode = code & 0xf; if (opcode < 9) { count = CVAL(input); count |= CVAL(input) << 8; } else { count = (opcode < 0xb) ? 8 : 1; } offset = 0; break; default: opcode >>= 1; count = code & 0x1f; offset = 32; break; } /* Handle strange cases for counts */ if (offset != 0) { isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) { if (isfillormix) count = CVAL(input) + 1; else count = CVAL(input) + offset; } else if (isfillormix) { count <<= 3; } } /* Read preliminary data */ switch (opcode) { case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (prevline == NULL))) insertmix = True; break; case 8: /* Bicolour */ colour1[0] = CVAL(input); colour1[1] = CVAL(input); colour1[2] = CVAL(input); case 3: /* Colour */ colour2[0] = CVAL(input); colour2[1] = CVAL(input); colour2[2] = CVAL(input); break; case 6: /* SetMix/Mix */ case 7: /* SetMix/FillOrMix */ mix[0] = CVAL(input); mix[1] = CVAL(input); mix[2] = CVAL(input); opcode -= 5; break; case 9: /* FillOrMix_1 */ mask = 0x03; opcode = 0x02; fom_mask = 3; break; case 0x0a: /* FillOrMix_2 */ mask = 0x05; opcode = 0x02; fom_mask = 5; break; } lastopcode = opcode; mixmask = 0; /* Output body */ while (count > 0) { if (x >= width) { if (height <= 0) return False; x = 0; height--; prevline = line; line = output + height * (width * 3); } switch (opcode) { case 0: /* Fill */ if (insertmix) { if (prevline == NULL) { line[x * 3] = mix[0]; line[x * 3 + 1] = mix[1]; line[x * 3 + 2] = mix[2]; } else { line[x * 3] = prevline[x * 3] ^ mix[0]; line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1]; line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2]; } insertmix = False; count--; x++; } if (prevline == NULL) { REPEAT ( line[x * 3] = 0; line[x * 3 + 1] = 0; line[x * 3 + 2] = 0; ) } else { REPEAT ( line[x * 3] = prevline[x * 3]; line[x * 3 + 1] = prevline[x * 3 + 1]; line[x * 3 + 2] = prevline[x * 3 + 2]; ) } break; case 1: /* Mix */ if (prevline == NULL) { REPEAT ( line[x * 3] = mix[0]; line[x * 3 + 1] = mix[1]; line[x * 3 + 2] = mix[2]; ) } else { REPEAT ( line[x * 3] = prevline[x * 3] ^ mix[0]; line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1]; line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2]; ) } break; case 2: /* Fill or Mix */ if (prevline == NULL) { REPEAT ( MASK_UPDATE(); if (mask & mixmask) { line[x * 3] = mix[0]; line[x * 3 + 1] = mix[1]; line[x * 3 + 2] = mix[2]; } else { line[x * 3] = 0; line[x * 3 + 1] = 0; line[x * 3 + 2] = 0; } ) } else { REPEAT ( MASK_UPDATE(); if (mask & mixmask) { line[x * 3] = prevline[x * 3] ^ mix [0]; line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix [1]; line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix [2]; } else { line[x * 3] = prevline[x * 3]; line[x * 3 + 1] = prevline[x * 3 + 1]; line[x * 3 + 2] = prevline[x * 3 + 2]; } ) } break; case 3: /* Colour */ REPEAT ( line[x * 3] = colour2 [0]; line[x * 3 + 1] = colour2 [1]; line[x * 3 + 2] = colour2 [2]; ) break; case 4: /* Copy */ REPEAT ( line[x * 3] = CVAL(input); line[x * 3 + 1] = CVAL(input); line[x * 3 + 2] = CVAL(input); ) break; case 8: /* Bicolour */ REPEAT ( if (bicolour) { line[x * 3] = colour2[0]; line[x * 3 + 1] = colour2[1]; line[x * 3 + 2] = colour2[2]; bicolour = False; } else { line[x * 3] = colour1[0]; line[x * 3 + 1] = colour1[1]; line[x * 3 + 2] = colour1[2]; bicolour = True; count++; } ) break; case 0xd: /* White */ REPEAT ( line[x * 3] = 0xff; line[x * 3 + 1] = 0xff; line[x * 3 + 2] = 0xff; ) break; case 0xe: /* Black */ REPEAT ( line[x * 3] = 0; line[x * 3 + 1] = 0; line[x * 3 + 2] = 0; ) break; default: unimpl("bitmap opcode 0x%x\n", opcode); return False; } } } return True; } /* decompress a colour plane */ static int process_plane(uint8 * in, int width, int height, uint8 * out, int size) { int indexw; int indexh; int code; int collen; int replen; int color; int x; int revcode; uint8 * last_line; uint8 * this_line; uint8 * org_in; uint8 * org_out; org_in = in; org_out = out; last_line = 0; indexh = 0; while (indexh < height) { out = (org_out + width * height * 4) - ((indexh + 1) * width * 4); color = 0; this_line = out; indexw = 0; if (last_line == 0) { while (indexw < width) { code = CVAL(in); replen = code & 0xf; collen = (code >> 4) & 0xf; revcode = (replen << 4) | collen; if ((revcode <= 47) && (revcode >= 16)) { replen = revcode; collen = 0; } while (collen > 0) { color = CVAL(in); *out = color; out += 4; indexw++; collen--; } while (replen > 0) { *out = color; out += 4; indexw++; replen--; } } } else { while (indexw < width) { code = CVAL(in); replen = code & 0xf; collen = (code >> 4) & 0xf; revcode = (replen << 4) | collen; if ((revcode <= 47) && (revcode >= 16)) { replen = revcode; collen = 0; } while (collen > 0) { x = CVAL(in); if (x & 1) { x = x >> 1; x = x + 1; color = -x; } else { x = x >> 1; color = x; } x = last_line[indexw * 4] + color; *out = x; out += 4; indexw++; collen--; } while (replen > 0) { x = last_line[indexw * 4] + color; *out = x; out += 4; indexw++; replen--; } } } indexh++; last_line = this_line; } return (int) (in - org_in); } /* 4 byte bitmap decompress */ static RD_BOOL bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size) { int code; int bytes_pro; int total_pro; code = CVAL(input); if (code != 0x10) { return False; } total_pro = 1; bytes_pro = process_plane(input, width, height, output + 3, size - total_pro); total_pro += bytes_pro; input += bytes_pro; bytes_pro = process_plane(input, width, height, output + 2, size - total_pro); total_pro += bytes_pro; input += bytes_pro; bytes_pro = process_plane(input, width, height, output + 1, size - total_pro); total_pro += bytes_pro; input += bytes_pro; bytes_pro = process_plane(input, width, height, output + 0, size - total_pro); total_pro += bytes_pro; return size == total_pro; } /* main decompress function */ RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp) { RD_BOOL rv = False; switch (Bpp) { case 1: rv = bitmap_decompress1(output, width, height, input, size); break; case 2: rv = bitmap_decompress2(output, width, height, input, size); break; case 3: rv = bitmap_decompress3(output, width, height, input, size); break; case 4: rv = bitmap_decompress4(output, width, height, input, size); break; default: unimpl("Bpp %d\n", Bpp); break; } return rv; } /* *INDENT-ON* */ rdesktop-1.8.3/cache.c0000664000770100510440000002404511551302500013501 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Cache routines Copyright (C) Matthew Chapman 1999-2008 Copyright (C) Jeroen Meijer 2005 Copyright 2003-2011 Peter Astrand for Cendio AB 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 3 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, see . */ #include "rdesktop.h" /* BITMAP CACHE */ extern int g_pstcache_fd[]; #define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0])) #define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0) #define TO_TOP -1 #define NOT_SET -1 #define IS_SET(idx) (idx >= 0) /* * TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest cpu utilisation but using * a positive value will hopefully result in less frequently used bitmaps having a greater chance * of being evicted from the cache, and therby reducing the need to load bitmaps from disk. * (Jeroen) */ #define BUMP_COUNT 40 struct bmpcache_entry { RD_HBITMAP bitmap; sint16 previous; sint16 next; }; static struct bmpcache_entry g_bmpcache[3][0xa00]; static RD_HBITMAP g_volatile_bc[3]; static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET }; static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET }; static int g_bmpcache_count[3]; /* Setup the bitmap cache lru/mru linked list */ void cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count) { int n = count, c = 0; sint16 n_idx; /* find top, skip evicted bitmaps */ while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL); if (n < 0) { g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET; return; } g_bmpcache_mru[id] = idx[n]; g_bmpcache[id][idx[n]].next = NOT_SET; n_idx = idx[n]; c++; /* link list */ while (n >= 0) { /* skip evicted bitmaps */ while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL); if (n < 0) break; g_bmpcache[id][n_idx].previous = idx[n]; g_bmpcache[id][idx[n]].next = n_idx; n_idx = idx[n]; c++; } g_bmpcache[id][n_idx].previous = NOT_SET; g_bmpcache_lru[id] = n_idx; if (c != g_bmpcache_count[id]) { error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c, g_bmpcache_count[id]); exit(EX_SOFTWARE); } } /* Move a bitmap to a new position in the linked list. */ void cache_bump_bitmap(uint8 id, uint16 idx, int bump) { int p_idx, n_idx, n; if (!IS_PERSISTENT(id)) return; if (g_bmpcache_mru[id] == idx) return; DEBUG_RDP5(("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump)); n_idx = g_bmpcache[id][idx].next; p_idx = g_bmpcache[id][idx].previous; if (IS_SET(n_idx)) { /* remove */ --g_bmpcache_count[id]; if (IS_SET(p_idx)) g_bmpcache[id][p_idx].next = n_idx; else g_bmpcache_lru[id] = n_idx; if (IS_SET(n_idx)) g_bmpcache[id][n_idx].previous = p_idx; else g_bmpcache_mru[id] = p_idx; } else { p_idx = NOT_SET; n_idx = g_bmpcache_lru[id]; } if (bump >= 0) { for (n = 0; n < bump && IS_SET(n_idx); n++) { p_idx = n_idx; n_idx = g_bmpcache[id][p_idx].next; } } else { p_idx = g_bmpcache_mru[id]; n_idx = NOT_SET; } /* insert */ ++g_bmpcache_count[id]; g_bmpcache[id][idx].previous = p_idx; g_bmpcache[id][idx].next = n_idx; if (p_idx >= 0) g_bmpcache[id][p_idx].next = idx; else g_bmpcache_lru[id] = idx; if (n_idx >= 0) g_bmpcache[id][n_idx].previous = idx; else g_bmpcache_mru[id] = idx; } /* Evict the least-recently used bitmap from the cache */ void cache_evict_bitmap(uint8 id) { uint16 idx; int n_idx; if (!IS_PERSISTENT(id)) return; idx = g_bmpcache_lru[id]; n_idx = g_bmpcache[id][idx].next; DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=%p\n", id, idx, n_idx, g_bmpcache[id][idx].bitmap)); ui_destroy_bitmap(g_bmpcache[id][idx].bitmap); --g_bmpcache_count[id]; g_bmpcache[id][idx].bitmap = 0; g_bmpcache_lru[id] = n_idx; g_bmpcache[id][n_idx].previous = NOT_SET; pstcache_touch_bitmap(id, idx, 0); } /* Retrieve a bitmap from the cache */ RD_HBITMAP cache_get_bitmap(uint8 id, uint16 idx) { if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0]))) { if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx)) { if (IS_PERSISTENT(id)) cache_bump_bitmap(id, idx, BUMP_COUNT); return g_bmpcache[id][idx].bitmap; } } else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff)) { return g_volatile_bc[id]; } error("get bitmap %d:%d\n", id, idx); return NULL; } /* Store a bitmap in the cache */ void cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap) { RD_HBITMAP old; if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0]))) { old = g_bmpcache[id][idx].bitmap; if (old != NULL) ui_destroy_bitmap(old); g_bmpcache[id][idx].bitmap = bitmap; if (IS_PERSISTENT(id)) { if (old == NULL) g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET; cache_bump_bitmap(id, idx, TO_TOP); if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS) cache_evict_bitmap(id); } } else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff)) { old = g_volatile_bc[id]; if (old != NULL) ui_destroy_bitmap(old); g_volatile_bc[id] = bitmap; } else { error("put bitmap %d:%d\n", id, idx); } } /* Updates the persistent bitmap cache MRU information on exit */ void cache_save_state(void) { uint32 id = 0, t = 0; int idx; for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++) if (IS_PERSISTENT(id)) { DEBUG_RDP5(("Saving cache state for bitmap cache %d...", id)); idx = g_bmpcache_lru[id]; while (idx >= 0) { pstcache_touch_bitmap(id, idx, ++t); idx = g_bmpcache[id][idx].next; } DEBUG_RDP5((" %d stamps written.\n", t)); } } /* FONT CACHE */ static FONTGLYPH g_fontcache[12][256]; /* Retrieve a glyph from the font cache */ FONTGLYPH * cache_get_font(uint8 font, uint16 character) { FONTGLYPH *glyph; if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0]))) { glyph = &g_fontcache[font][character]; if (glyph->pixmap != NULL) return glyph; } error("get font %d:%d\n", font, character); return NULL; } /* Store a glyph in the font cache */ void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap) { FONTGLYPH *glyph; if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0]))) { glyph = &g_fontcache[font][character]; if (glyph->pixmap != NULL) ui_destroy_glyph(glyph->pixmap); glyph->offset = offset; glyph->baseline = baseline; glyph->width = width; glyph->height = height; glyph->pixmap = pixmap; } else { error("put font %d:%d\n", font, character); } } /* TEXT CACHE */ static DATABLOB g_textcache[256]; /* Retrieve a text item from the cache */ DATABLOB * cache_get_text(uint8 cache_id) { DATABLOB *text; text = &g_textcache[cache_id]; return text; } /* Store a text item in the cache */ void cache_put_text(uint8 cache_id, void *data, int length) { DATABLOB *text; text = &g_textcache[cache_id]; if (text->data != NULL) xfree(text->data); text->data = xmalloc(length); text->size = length; memcpy(text->data, data, length); } /* DESKTOP CACHE */ static uint8 g_deskcache[0x38400 * 4]; /* Retrieve desktop data from the cache */ uint8 * cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel) { int length = cx * cy * bytes_per_pixel; if (offset > sizeof(g_deskcache)) offset = 0; if ((offset + length) <= sizeof(g_deskcache)) { return &g_deskcache[offset]; } error("get desktop %d:%d\n", offset, length); return NULL; } /* Store desktop data in the cache */ void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data) { int length = cx * cy * bytes_per_pixel; if (offset > sizeof(g_deskcache)) offset = 0; if ((offset + length) <= sizeof(g_deskcache)) { cx *= bytes_per_pixel; while (cy--) { memcpy(&g_deskcache[offset], data, cx); data += scanline; offset += cx; } } else { error("put desktop %d:%d\n", offset, length); } } /* CURSOR CACHE */ static RD_HCURSOR g_cursorcache[0x20]; /* Retrieve cursor from cache */ RD_HCURSOR cache_get_cursor(uint16 cache_idx) { RD_HCURSOR cursor; if (cache_idx < NUM_ELEMENTS(g_cursorcache)) { cursor = g_cursorcache[cache_idx]; if (cursor != NULL) return cursor; } error("get cursor %d\n", cache_idx); return NULL; } /* Store cursor in cache */ void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor) { RD_HCURSOR old; if (cache_idx < NUM_ELEMENTS(g_cursorcache)) { old = g_cursorcache[cache_idx]; if (old != NULL) ui_destroy_cursor(old); g_cursorcache[cache_idx] = cursor; } else { error("put cursor %d\n", cache_idx); } } /* BRUSH CACHE */ /* index 0 is 2 colour brush, index 1 is muti colour brush */ static BRUSHDATA g_brushcache[2][64]; /* Retrieve brush from cache */ BRUSHDATA * cache_get_brush_data(uint8 colour_code, uint8 idx) { colour_code = colour_code == 1 ? 0 : 1; if (idx < NUM_ELEMENTS(g_brushcache[0])) { return &g_brushcache[colour_code][idx]; } error("get brush %d %d\n", colour_code, idx); return NULL; } /* Store brush in cache */ /* this function takes over the data pointer in struct, eg, caller gives it up */ void cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data) { BRUSHDATA *bd; colour_code = colour_code == 1 ? 0 : 1; if (idx < NUM_ELEMENTS(g_brushcache[0])) { bd = &g_brushcache[colour_code][idx]; if (bd->data != 0) { xfree(bd->data); } memcpy(bd, brush_data, sizeof(BRUSHDATA)); } else { error("put brush %d %d\n", colour_code, idx); } } rdesktop-1.8.3/channels.c0000664000770100510440000001155111766542444014254 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - Virtual channels Copyright 2003 Erik Forsberg for Cendio AB Copyright (C) Matthew Chapman 2003-2008 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 3 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, see . */ #include "rdesktop.h" #define MAX_CHANNELS 6 #define CHANNEL_CHUNK_LENGTH 1600 #define CHANNEL_FLAG_FIRST 0x01 #define CHANNEL_FLAG_LAST 0x02 #define CHANNEL_FLAG_SHOW_PROTOCOL 0x10 extern RDP_VERSION g_rdp_version; extern RD_BOOL g_encryption; VCHANNEL g_channels[MAX_CHANNELS]; unsigned int g_num_channels; /* FIXME: We should use the information in TAG_SRV_CHANNELS to map RDP5 channels to MCS channels. The format of TAG_SRV_CHANNELS seems to be global_channel_no (uint16le) number_of_other_channels (uint16le) ..followed by uint16les for the other channels. */ VCHANNEL * channel_register(char *name, uint32 flags, void (*callback) (STREAM)) { VCHANNEL *channel; if (g_rdp_version < RDP_V5) return NULL; if (g_num_channels >= MAX_CHANNELS) { error("Channel table full, increase MAX_CHANNELS\n"); return NULL; } channel = &g_channels[g_num_channels]; channel->mcs_id = MCS_GLOBAL_CHANNEL + 1 + g_num_channels; strncpy(channel->name, name, 8); channel->flags = flags; channel->process = callback; g_num_channels++; return channel; } STREAM channel_init(VCHANNEL * channel, uint32 length) { STREAM s; s = sec_init(g_encryption ? SEC_ENCRYPT : 0, length + 8); s_push_layer(s, channel_hdr, 8); return s; } void channel_send(STREAM s, VCHANNEL * channel) { uint32 length, flags; uint32 thislength, remaining; uint8 *data; #ifdef WITH_SCARD scard_lock(SCARD_LOCK_CHANNEL); #endif /* first fragment sent in-place */ s_pop_layer(s, channel_hdr); length = s->end - s->p - 8; DEBUG_CHANNEL(("channel_send, length = %d\n", length)); thislength = MIN(length, CHANNEL_CHUNK_LENGTH); /* Note: In the original clipboard implementation, this number was 1592, not 1600. However, I don't remember the reason and 1600 seems to work so.. This applies only to *this* length, not the length of continuation or ending packets. */ remaining = length - thislength; flags = (remaining == 0) ? CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST : CHANNEL_FLAG_FIRST; if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL) flags |= CHANNEL_FLAG_SHOW_PROTOCOL; out_uint32_le(s, length); out_uint32_le(s, flags); data = s->end = s->p + thislength; DEBUG_CHANNEL(("Sending %d bytes with FLAG_FIRST\n", thislength)); sec_send_to_channel(s, g_encryption ? SEC_ENCRYPT : 0, channel->mcs_id); /* subsequent segments copied (otherwise would have to generate headers backwards) */ while (remaining > 0) { thislength = MIN(remaining, CHANNEL_CHUNK_LENGTH); remaining -= thislength; flags = (remaining == 0) ? CHANNEL_FLAG_LAST : 0; if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL) flags |= CHANNEL_FLAG_SHOW_PROTOCOL; DEBUG_CHANNEL(("Sending %d bytes with flags %d\n", thislength, flags)); s = sec_init(g_encryption ? SEC_ENCRYPT : 0, thislength + 8); out_uint32_le(s, length); out_uint32_le(s, flags); out_uint8p(s, data, thislength); s_mark_end(s); sec_send_to_channel(s, g_encryption ? SEC_ENCRYPT : 0, channel->mcs_id); data += thislength; } #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_CHANNEL); #endif } void channel_process(STREAM s, uint16 mcs_channel) { uint32 length, flags; uint32 thislength; VCHANNEL *channel = NULL; unsigned int i; STREAM in; for (i = 0; i < g_num_channels; i++) { channel = &g_channels[i]; if (channel->mcs_id == mcs_channel) break; } if (i >= g_num_channels) return; in_uint32_le(s, length); in_uint32_le(s, flags); if ((flags & CHANNEL_FLAG_FIRST) && (flags & CHANNEL_FLAG_LAST)) { /* single fragment - pass straight up */ channel->process(s); } else { /* add fragment to defragmentation buffer */ in = &channel->in; if (flags & CHANNEL_FLAG_FIRST) { if (length > in->size) { in->data = (uint8 *) xrealloc(in->data, length); in->size = length; } in->p = in->data; } thislength = MIN(s->end - s->p, in->data + in->size - in->p); memcpy(in->p, s->p, thislength); in->p += thislength; if (flags & CHANNEL_FLAG_LAST) { in->end = in->p; in->p = in->data; channel->process(in); } } } rdesktop-1.8.3/cliprdr.c0000664000770100510440000001164211640565273014115 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - Clipboard functions Copyright 2003 Erik Forsberg for Cendio AB Copyright (C) Matthew Chapman 2003-2008 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 3 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, see . */ #include "rdesktop.h" #define CLIPRDR_CONNECT 1 #define CLIPRDR_FORMAT_ANNOUNCE 2 #define CLIPRDR_FORMAT_ACK 3 #define CLIPRDR_DATA_REQUEST 4 #define CLIPRDR_DATA_RESPONSE 5 #define CLIPRDR_REQUEST 0 #define CLIPRDR_RESPONSE 1 #define CLIPRDR_ERROR 2 static VCHANNEL *cliprdr_channel; static uint8 *last_formats = NULL; static uint32 last_formats_length = 0; static void cliprdr_send_packet(uint16 type, uint16 status, uint8 * data, uint32 length) { STREAM s; DEBUG_CLIPBOARD(("CLIPRDR send: type=%d, status=%d, length=%d\n", type, status, length)); s = channel_init(cliprdr_channel, length + 12); out_uint16_le(s, type); out_uint16_le(s, status); out_uint32_le(s, length); out_uint8p(s, data, length); out_uint32(s, 0); /* pad? */ s_mark_end(s); channel_send(s, cliprdr_channel); } /* Helper which announces our readiness to supply clipboard data in a single format (such as CF_TEXT) to the RDP side. To announce more than one format at a time, use cliprdr_send_native_format_announce. */ void cliprdr_send_simple_native_format_announce(uint32 format) { uint8 buffer[36]; DEBUG_CLIPBOARD(("cliprdr_send_simple_native_format_announce\n")); buf_out_uint32(buffer, format); memset(buffer + 4, 0, sizeof(buffer) - 4); /* description */ cliprdr_send_native_format_announce(buffer, sizeof(buffer)); } /* Announces our readiness to supply clipboard data in multiple formats, each denoted by a 36-byte format descriptor of [ uint32 format + 32-byte description ]. */ void cliprdr_send_native_format_announce(uint8 * formats_data, uint32 formats_data_length) { DEBUG_CLIPBOARD(("cliprdr_send_native_format_announce\n")); cliprdr_send_packet(CLIPRDR_FORMAT_ANNOUNCE, CLIPRDR_REQUEST, formats_data, formats_data_length); if (formats_data != last_formats) { if (last_formats) xfree(last_formats); last_formats = xmalloc(formats_data_length); memcpy(last_formats, formats_data, formats_data_length); last_formats_length = formats_data_length; } } void cliprdr_send_data_request(uint32 format) { uint8 buffer[4]; DEBUG_CLIPBOARD(("cliprdr_send_data_request\n")); buf_out_uint32(buffer, format); cliprdr_send_packet(CLIPRDR_DATA_REQUEST, CLIPRDR_REQUEST, buffer, sizeof(buffer)); } void cliprdr_send_data(uint8 * data, uint32 length) { DEBUG_CLIPBOARD(("cliprdr_send_data\n")); cliprdr_send_packet(CLIPRDR_DATA_RESPONSE, CLIPRDR_RESPONSE, data, length); } static void cliprdr_process(STREAM s) { uint16 type, status; uint32 length, format; uint8 *data; in_uint16_le(s, type); in_uint16_le(s, status); in_uint32_le(s, length); data = s->p; DEBUG_CLIPBOARD(("CLIPRDR recv: type=%d, status=%d, length=%d\n", type, status, length)); if (status == CLIPRDR_ERROR) { switch (type) { case CLIPRDR_FORMAT_ACK: /* FIXME: We seem to get this when we send an announce while the server is still processing a paste. Try sending another announce. */ cliprdr_send_native_format_announce(last_formats, last_formats_length); break; case CLIPRDR_DATA_RESPONSE: ui_clip_request_failed(); break; default: DEBUG_CLIPBOARD(("CLIPRDR error (type=%d)\n", type)); } return; } switch (type) { case CLIPRDR_CONNECT: ui_clip_sync(); break; case CLIPRDR_FORMAT_ANNOUNCE: ui_clip_format_announce(data, length); cliprdr_send_packet(CLIPRDR_FORMAT_ACK, CLIPRDR_RESPONSE, NULL, 0); return; case CLIPRDR_FORMAT_ACK: break; case CLIPRDR_DATA_REQUEST: in_uint32_le(s, format); ui_clip_request_data(format); break; case CLIPRDR_DATA_RESPONSE: ui_clip_handle_data(data, length); break; case 7: /* TODO: W2K3 SP1 sends this on connect with a value of 1 */ break; default: unimpl("CLIPRDR packet type %d\n", type); } } void cliprdr_set_mode(const char *optarg) { ui_clip_set_mode(optarg); } RD_BOOL cliprdr_init(void) { cliprdr_channel = channel_register("cliprdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL, cliprdr_process); return (cliprdr_channel != NULL); } rdesktop-1.8.3/cssp.c0000664000770100510440000005455412400056224013421 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. CredSSP layer and kerberos support. Copyright 2012-2013 Henrik Andersson for Cendio AB 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 3 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, see . */ #include #include "rdesktop.h" extern RD_BOOL g_use_password_as_pin; extern char *g_sc_csp_name; extern char *g_sc_reader_name; extern char *g_sc_card_name; extern char *g_sc_container_name; static gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc = { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; static void s_realloc(STREAM s, unsigned int size) { unsigned char *data; if (s->size >= size) return; data = s->data; s->size = size; s->data = xrealloc(data, size); s->p = s->data + (s->p - data); s->end = s->data + (s->end - data); s->iso_hdr = s->data + (s->iso_hdr - data); s->mcs_hdr = s->data + (s->mcs_hdr - data); s->sec_hdr = s->data + (s->sec_hdr - data); s->rdp_hdr = s->data + (s->rdp_hdr - data); s->channel_hdr = s->data + (s->channel_hdr - data); } static void s_free(STREAM s) { free(s->data); free(s); } static STREAM ber_wrap_hdr_data(int tagval, STREAM in) { STREAM out; int size = s_length(in) + 16; out = xmalloc(sizeof(struct stream)); memset(out, 0, sizeof(struct stream)); out->data = xmalloc(size); out->size = size; out->p = out->data; ber_out_header(out, tagval, s_length(in)); out_uint8p(out, in->data, s_length(in)); s_mark_end(out); return out; } static void cssp_gss_report_error(OM_uint32 code, char *str, OM_uint32 major_status, OM_uint32 minor_status) { OM_uint32 msgctx = 0, ms; gss_buffer_desc status_string; error("GSS error [%d:%d:%d]: %s\n", (major_status & 0xff000000) >> 24, // Calling error (major_status & 0xff0000) >> 16, // Routine error major_status & 0xffff, // Supplementary info bits str); do { ms = gss_display_status(&minor_status, major_status, code, GSS_C_NULL_OID, &msgctx, &status_string); if (ms != GSS_S_COMPLETE) continue; error(" - %s\n", status_string.value); } while (ms == GSS_S_COMPLETE && msgctx); } static RD_BOOL cssp_gss_mech_available(gss_OID mech) { int mech_found; OM_uint32 major_status, minor_status; gss_OID_set mech_set; mech_found = 0; if (mech == GSS_C_NO_OID) return True; major_status = gss_indicate_mechs(&minor_status, &mech_set); if (!mech_set) return False; if (GSS_ERROR(major_status)) { cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to get available mechs on system", major_status, minor_status); return False; } gss_test_oid_set_member(&minor_status, mech, mech_set, &mech_found); if (GSS_ERROR(major_status)) { cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to match mechanism in set", major_status, minor_status); return False; } if (!mech_found) return False; return True; } static RD_BOOL cssp_gss_get_service_name(char *server, gss_name_t * name) { gss_buffer_desc output; OM_uint32 major_status, minor_status; const char service_name[] = "TERMSRV"; gss_OID type = (gss_OID) GSS_C_NT_HOSTBASED_SERVICE; int size = (strlen(service_name) + 1 + strlen(server) + 1); output.value = malloc(size); snprintf(output.value, size, "%s@%s", service_name, server); output.length = strlen(output.value) + 1; major_status = gss_import_name(&minor_status, &output, type, name); if (GSS_ERROR(major_status)) { cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to create service principal name", major_status, minor_status); return False; } gss_release_buffer(&minor_status, &output); return True; } static RD_BOOL cssp_gss_wrap(gss_ctx_id_t * ctx, STREAM in, STREAM out) { int conf_state; OM_uint32 major_status; OM_uint32 minor_status; gss_buffer_desc inbuf, outbuf; inbuf.value = in->data; inbuf.length = s_length(in); major_status = gss_wrap(&minor_status, ctx, True, GSS_C_QOP_DEFAULT, &inbuf, &conf_state, &outbuf); if (major_status != GSS_S_COMPLETE) { cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to encrypt and sign message", major_status, minor_status); return False; } if (!conf_state) { error("GSS Confidentiality failed, no encryption of message performed."); return False; } // write enc data to out stream out->data = out->p = xmalloc(outbuf.length); out->size = outbuf.length; out_uint8p(out, outbuf.value, outbuf.length); s_mark_end(out); gss_release_buffer(&minor_status, &outbuf); return True; } static RD_BOOL cssp_gss_unwrap(gss_ctx_id_t * ctx, STREAM in, STREAM out) { OM_uint32 major_status; OM_uint32 minor_status; gss_qop_t qop_state; gss_buffer_desc inbuf, outbuf; int conf_state; inbuf.value = in->data; inbuf.length = s_length(in); major_status = gss_unwrap(&minor_status, ctx, &inbuf, &outbuf, &conf_state, &qop_state); if (major_status != GSS_S_COMPLETE) { cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to decrypt message", major_status, minor_status); return False; } out->data = out->p = xmalloc(outbuf.length); out->size = outbuf.length; out_uint8p(out, outbuf.value, outbuf.length); s_mark_end(out); gss_release_buffer(&minor_status, &outbuf); return True; } #ifdef WITH_DEBUG_CREDSSP void streamsave(STREAM s, char *fn) { FILE *f = fopen(fn, "wb"); fwrite(s->data, s_length(s), 1, f); fclose(f); } #endif static STREAM cssp_encode_tspasswordcreds(char *username, char *password, char *domain) { STREAM out, h1, h2; struct stream tmp = { 0 }; struct stream message = { 0 }; memset(&tmp, 0, sizeof(tmp)); memset(&message, 0, sizeof(message)); // domainName [0] s_realloc(&tmp, 4 + strlen(domain) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, domain, strlen(domain) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); // userName [1] s_realloc(&tmp, 4 + strlen(username) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, username, strlen(username) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); // password [2] s_realloc(&tmp, 4 + strlen(password) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, password, strlen(password) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); // build message out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message); // cleanup xfree(tmp.data); xfree(message.data); return out; } /* KeySpecs from wincrypt.h */ #define AT_KEYEXCHANGE 1 #define AT_SIGNATURE 2 static STREAM cssp_encode_tscspdatadetail(unsigned char keyspec, char *card, char *reader, char *container, char *csp) { STREAM out; STREAM h1, h2; struct stream tmp = { 0 }; struct stream message = { 0 }; // keySpec [0] s_realloc(&tmp, sizeof(uint8)); s_reset(&tmp); out_uint8(&tmp, keyspec); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); // cardName [1] if (card) { s_realloc(&tmp, 4 + strlen(card) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, card, strlen(card) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); } // readerName [2] if (reader) { s_realloc(&tmp, 4 + strlen(reader) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, reader, strlen(reader) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); } // containerName [3] if (container) { s_realloc(&tmp, 4 + strlen(container) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, container, strlen(container) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); } // cspName [4] if (csp) { s_realloc(&tmp, 4 + strlen(csp) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, csp, strlen(csp) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 4, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); } s_mark_end(&message); // build message out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message); // cleanup free(tmp.data); free(message.data); return out; } static STREAM cssp_encode_tssmartcardcreds(char *username, char *password, char *domain) { STREAM out, h1, h2; struct stream tmp = { 0 }; struct stream message = { 0 }; // pin [0] s_realloc(&tmp, strlen(password) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, password, strlen(password) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); // cspData[1] h2 = cssp_encode_tscspdatadetail(AT_KEYEXCHANGE, g_sc_card_name, g_sc_reader_name, g_sc_container_name, g_sc_csp_name); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); // userHint [2] if (username && strlen(username)) { s_realloc(&tmp, strlen(username) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, username, strlen(username) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); } // domainHint [3] if (domain && strlen(domain)) { s_realloc(&tmp, strlen(domain) * sizeof(uint16)); s_reset(&tmp); rdp_out_unistr(&tmp, domain, strlen(domain) * sizeof(uint16)); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); } s_mark_end(&message); // build message out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message); // cleanup free(tmp.data); free(message.data); return out; } STREAM cssp_encode_tscredentials(char *username, char *password, char *domain) { STREAM out; STREAM h1, h2, h3; struct stream tmp = { 0 }; struct stream message = { 0 }; // credType [0] s_realloc(&tmp, sizeof(uint8)); s_reset(&tmp); if (g_use_password_as_pin == False) { out_uint8(&tmp, 1); // TSPasswordCreds } else { out_uint8(&tmp, 2); // TSSmartCardCreds } s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); // credentials [1] if (g_use_password_as_pin == False) { h3 = cssp_encode_tspasswordcreds(username, password, domain); } else { h3 = cssp_encode_tssmartcardcreds(username, password, domain); } h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, h3); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h3); s_free(h2); s_free(h1); // Construct ASN.1 message out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message); #if WITH_DEBUG_CREDSSP streamsave(out, "tscredentials.raw"); printf("Out TSCredentials %ld bytes\n", s_length(out)); hexdump(out->data, s_length(out)); #endif // cleanup xfree(message.data); xfree(tmp.data); return out; } RD_BOOL cssp_send_tsrequest(STREAM token, STREAM auth, STREAM pubkey) { STREAM s; STREAM h1, h2, h3, h4, h5; struct stream tmp = { 0 }; struct stream message = { 0 }; memset(&message, 0, sizeof(message)); memset(&tmp, 0, sizeof(tmp)); // version [0] s_realloc(&tmp, sizeof(uint8)); s_reset(&tmp); out_uint8(&tmp, 2); s_mark_end(&tmp); h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); // negoToken [1] if (token && s_length(token)) { h5 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, token); h4 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h5); h3 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, h4); h2 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, h3); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h5); s_free(h4); s_free(h3); s_free(h2); s_free(h1); } // authInfo [2] if (auth && s_length(auth)) { h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, auth); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_free(h2); s_free(h1); } // pubKeyAuth [3] if (pubkey && s_length(pubkey)) { h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, pubkey); h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2); s_realloc(&message, s_length(&message) + s_length(h1)); out_uint8p(&message, h1->data, s_length(h1)); s_mark_end(&message); s_free(h2); s_free(h1); } s_mark_end(&message); // Construct ASN.1 Message // Todo: can h1 be send directly instead of tcp_init() approach h1 = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message); s = tcp_init(s_length(h1)); out_uint8p(s, h1->data, s_length(h1)); s_mark_end(s); s_free(h1); #if WITH_DEBUG_CREDSSP streamsave(s, "tsrequest_out.raw"); printf("Out TSRequest %ld bytes\n", s_length(s)); hexdump(s->data, s_length(s)); #endif tcp_send(s); // cleanup xfree(message.data); xfree(tmp.data); return True; } RD_BOOL cssp_read_tsrequest(STREAM token, STREAM pubkey) { STREAM s; int length; int tagval; s = tcp_recv(NULL, 4); if (s == NULL) return False; // verify ASN.1 header if (s->p[0] != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED)) { error("Expected BER_TAG_SEQUENCE|BER_TAG_CONSTRUCTED, got %x", s->p[0]); return False; } // peek at first 4 bytes to get full message length if (s->p[1] < 0x80) length = s->p[1] - 2; else if (s->p[1] == 0x81) length = s->p[2] - 1; else if (s->p[1] == 0x82) length = (s->p[2] << 8) | s->p[3]; else return False; // receive the remainings of message s = tcp_recv(s, length); #if WITH_DEBUG_CREDSSP streamsave(s, "tsrequest_in.raw"); printf("In TSRequest token %ld bytes\n", s_length(s)); hexdump(s->data, s_length(s)); #endif // parse the response and into nego token if (!ber_in_header(s, &tagval, &length) || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED)) return False; // version [0] if (!ber_in_header(s, &tagval, &length) || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0)) return False; in_uint8s(s, length); // negoToken [1] if (token) { if (!ber_in_header(s, &tagval, &length) || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1)) return False; if (!ber_in_header(s, &tagval, &length) || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED)) return False; if (!ber_in_header(s, &tagval, &length) || tagval != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED)) return False; if (!ber_in_header(s, &tagval, &length) || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0)) return False; if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING) return False; token->end = token->p = token->data; out_uint8p(token, s->p, length); s_mark_end(token); } // pubKey [3] if (pubkey) { if (!ber_in_header(s, &tagval, &length) || tagval != (BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3)) return False; if (!ber_in_header(s, &tagval, &length) || tagval != BER_TAG_OCTET_STRING) return False; pubkey->data = pubkey->p = s->p; pubkey->end = pubkey->data + length; pubkey->size = length; } return True; } RD_BOOL cssp_connect(char *server, char *user, char *domain, char *password, STREAM s) { OM_uint32 actual_time; gss_cred_id_t cred; gss_buffer_desc input_tok, output_tok; gss_name_t target_name; OM_uint32 major_status, minor_status; int context_established = 0; gss_ctx_id_t gss_ctx; gss_OID desired_mech = &_gss_spnego_krb5_mechanism_oid_desc; STREAM ts_creds; struct stream token = { 0 }; struct stream pubkey = { 0 }; struct stream pubkey_cmp = { 0 }; // Verify that system gss support spnego if (!cssp_gss_mech_available(desired_mech)) { warning("CredSSP: System doesn't have support for desired authentication mechanism.\n"); return False; } // Get service name if (!cssp_gss_get_service_name(server, &target_name)) { warning("CredSSP: Failed to get target service name.\n"); return False; } // Establish tls connection to server if (!tcp_tls_connect()) { warning("CredSSP: Failed to establish TLS connection.\n"); return False; } tcp_tls_get_server_pubkey(&pubkey); #ifdef WITH_DEBUG_CREDSSP streamsave(&pubkey, "PubKey.raw"); #endif // Enter the spnego loop OM_uint32 actual_services; gss_OID actual_mech; struct stream blob = { 0 }; gss_ctx = GSS_C_NO_CONTEXT; cred = GSS_C_NO_CREDENTIAL; input_tok.length = 0; output_tok.length = 0; minor_status = 0; int i = 0; do { major_status = gss_init_sec_context(&minor_status, cred, &gss_ctx, target_name, desired_mech, GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &input_tok, &actual_mech, &output_tok, &actual_services, &actual_time); if (GSS_ERROR(major_status)) { if (i == 0) error("CredSSP: Initialize failed, do you have correct kerberos tgt initialized ?\n"); else error("CredSSP: Negotiation failed.\n"); #ifdef WITH_DEBUG_CREDSSP cssp_gss_report_error(GSS_C_GSS_CODE, "CredSSP: SPNEGO negotiation failed.", major_status, minor_status); #endif goto bail_out; } // validate required services if (!(actual_services & GSS_C_CONF_FLAG)) { error("CredSSP: Confidiality service required but is not available.\n"); goto bail_out; } // Send token to server if (output_tok.length != 0) { if (output_tok.length > token.size) s_realloc(&token, output_tok.length); s_reset(&token); out_uint8p(&token, output_tok.value, output_tok.length); s_mark_end(&token); if (!cssp_send_tsrequest(&token, NULL, NULL)) goto bail_out; (void) gss_release_buffer(&minor_status, &output_tok); } // Read token from server if (major_status & GSS_S_CONTINUE_NEEDED) { (void) gss_release_buffer(&minor_status, &input_tok); if (!cssp_read_tsrequest(&token, NULL)) goto bail_out; input_tok.value = token.data; input_tok.length = s_length(&token); } else { // Send encrypted pubkey for verification to server context_established = 1; if (!cssp_gss_wrap(gss_ctx, &pubkey, &blob)) goto bail_out; if (!cssp_send_tsrequest(NULL, NULL, &blob)) goto bail_out; context_established = 1; } i++; } while (!context_established); // read tsrequest response and decrypt for public key validation if (!cssp_read_tsrequest(NULL, &blob)) goto bail_out; if (!cssp_gss_unwrap(gss_ctx, &blob, &pubkey_cmp)) goto bail_out; pubkey_cmp.data[0] -= 1; // validate public key if (memcmp(pubkey.data, pubkey_cmp.data, s_length(&pubkey)) != 0) { error("CredSSP: Cannot guarantee integrity of server connection, MITM ? " "(public key data mismatch)\n"); goto bail_out; } // Send TSCredentials ts_creds = cssp_encode_tscredentials(user, password, domain); if (!cssp_gss_wrap(gss_ctx, ts_creds, &blob)) goto bail_out; s_free(ts_creds); if (!cssp_send_tsrequest(NULL, &blob, NULL)) goto bail_out; return True; bail_out: xfree(token.data); return False; } rdesktop-1.8.3/ctrl.c0000664000770100510440000002503112241141256013404 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Master/Slave remote controlling Copyright 2013 Henrik Andersson for Cendio AB 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 3 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, see . */ #include "rdesktop.h" #include "ssl.h" #include #include #include #include #include #include #include #include #define CTRL_LINEBUF_SIZE 1024 #define CTRL_RESULT_SIZE 32 #define RDESKTOP_CTRLSOCK_STORE "/.local/share/rdesktop/ctrl" #define CTRL_HASH_FLAG_SEAMLESS 1 #define ERR_RESULT_OK 0x00 #define ERR_RESULT_NO_SUCH_COMMAND 0xffffffff extern RD_BOOL g_seamless_rdp; extern uint8 g_static_rdesktop_salt_16[]; static RD_BOOL _ctrl_is_slave; static int ctrlsock; static char ctrlsock_name[PATH_MAX]; static struct _ctrl_slave_t *_ctrl_slaves; #define CMD_SEAMLESS_SPAWN "seamless.spawn" typedef struct _ctrl_slave_t { struct _ctrl_slave_t *prev, *next; int sock; char linebuf[CTRL_LINEBUF_SIZE]; } _ctrl_slave_t; static void _ctrl_slave_new(int sock) { _ctrl_slave_t *it, *ns; /* initialize new slave list item */ ns = (_ctrl_slave_t *) xmalloc(sizeof(_ctrl_slave_t)); memset(ns, 0, sizeof(_ctrl_slave_t)); ns->sock = sock; /* append new slave to end of list */ it = _ctrl_slaves; /* find last element in list */ while (it && it->next) it = it->next; /* if last found append new */ if (it) { it->next = ns; ns->prev = it; } else { /* no elemnts in list, lets add first */ _ctrl_slaves = ns; } } static void _ctrl_slave_disconnect(int sock) { _ctrl_slave_t *it; if (!_ctrl_slaves) return; it = _ctrl_slaves; /* find slave with sock */ while (it->next && it->sock != sock) it = it->next; if (it->sock == sock) { /* shutdown socket */ shutdown(sock, SHUT_RDWR); close(sock); /* remove item from list */ if (it == _ctrl_slaves) { if (it->next) _ctrl_slaves = it->next; else _ctrl_slaves = NULL; } if (it->prev) { (it->prev)->next = it->next; if (it->next) (it->next)->prev = it->prev; } else if (it->next) (it->next)->prev = NULL; xfree(it); } } static void _ctrl_command_result(_ctrl_slave_t * slave, int result) { char buf[64] = { 0 }; /* translate and send result code back to client */ if (result == 0) send(slave->sock, "OK\n", 3, 0); else { snprintf(buf, 64, "ERROR %x\n", result); send(slave->sock, buf, strlen(buf), 0); } } static void _ctrl_dispatch_command(_ctrl_slave_t * slave) { char *p; char *cmd; unsigned int res; /* unescape linebuffer */ cmd = utils_string_unescape(slave->linebuf); if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0) { /* process seamless spawn request */ p = strstr(cmd, "seamlessrdpshell.exe"); if (p) p += strlen("seamlessrdpshell.exe") + 1; else p = cmd + strlen(CMD_SEAMLESS_SPAWN) + 1; res = ERR_RESULT_OK; if (seamless_send_spawn(p) == (unsigned int) -1) res = 1; } else { res = ERR_RESULT_NO_SUCH_COMMAND; } xfree(cmd); _ctrl_command_result(slave, res); } static RD_BOOL _ctrl_verify_unix_socket() { int s, len; struct sockaddr_un saun; memset(&saun, 0, sizeof(struct sockaddr_un)); if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("Error creating ctrl client socket: socket()"); exit(1); } saun.sun_family = AF_UNIX; strcpy(saun.sun_path, ctrlsock_name); len = sizeof(saun.sun_family) + strlen(saun.sun_path); /* test connection */ if (connect(s, (struct sockaddr *) &saun, len) != 0) return False; shutdown(s, SHUT_RDWR); close(s); return True; } static void _ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize) { RDSSL_SHA1 sha1; uint8 out[20], delim; uint16 version; uint32 flags; /* version\0user\0domain\0host\0flags */ flags = 0; delim = '\0'; version = 0x0100; if (g_seamless_rdp) flags = CTRL_HASH_FLAG_SEAMLESS; rdssl_sha1_init(&sha1); rdssl_sha1_update(&sha1, (uint8 *) & version, sizeof(version)); rdssl_sha1_update(&sha1, &delim, 1); if (user) rdssl_sha1_update(&sha1, (uint8 *) user, strlen(user)); rdssl_sha1_update(&sha1, &delim, 1); if (domain) rdssl_sha1_update(&sha1, (uint8 *) domain, strlen(domain)); rdssl_sha1_update(&sha1, &delim, 1); if (host) rdssl_sha1_update(&sha1, (uint8 *) host, strlen(host)); rdssl_sha1_update(&sha1, &delim, 1); rdssl_sha1_update(&sha1, (uint8 *) & flags, sizeof(flags)); rdssl_sha1_final(&sha1, out); sec_hash_to_string(hash, hsize, out, sizeof(out)); } /** Initialize ctrl Ret values: <0 failure, 0 master, 1 client */ int ctrl_init(const char *user, const char *domain, const char *host) { struct stat st; struct sockaddr_un saun; char hash[41], path[PATH_MAX]; char *home; /* check if ctrl already initialized */ if (ctrlsock != 0 || _ctrl_is_slave) return 0; home = getenv("HOME"); if (home == NULL) { return -1; } /* get uniq hash for ctrlsock name */ _ctrl_create_hash(user, domain, host, hash, 41); snprintf(ctrlsock_name, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash); ctrlsock_name[sizeof(ctrlsock_name) - 1] = '\0'; /* make sure that ctrlsock store path exists */ snprintf(path, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE, home); path[sizeof(path) - 1] = '\0'; if (utils_mkdir_p(path, 0700) == -1) { perror(path); return -1; } /* check if ctrl socket already exist then this process becomes a client */ if (stat(ctrlsock_name, &st) == 0) { /* verify that unix socket is not stale */ if (_ctrl_verify_unix_socket() == True) { _ctrl_is_slave = True; return 1; } else { unlink(ctrlsock_name); } } /* setup ctrl socket and start listening for connections */ if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("Error creating ctrl socket:"); exit(1); } /* bind and start listening on server socket */ memset(&saun, 0, sizeof(struct sockaddr_un)); saun.sun_family = AF_UNIX; strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path)); if (bind(ctrlsock, (struct sockaddr *) &saun, sizeof(struct sockaddr_un)) < 0) { perror("Error binding ctrl socket:"); exit(1); } if (listen(ctrlsock, 5) < 0) { perror("Error listening on socket:"); exit(1); } /* add ctrl cleanup func to exit hooks */ atexit(ctrl_cleanup); return 0; } void ctrl_cleanup() { if (ctrlsock) { close(ctrlsock); unlink(ctrlsock_name); } } RD_BOOL ctrl_is_slave() { return _ctrl_is_slave; } void ctrl_add_fds(int *n, fd_set * rfds) { _ctrl_slave_t *it; if (ctrlsock == 0) return; FD_SET(ctrlsock, rfds); *n = MAX(*n, ctrlsock); /* add connected slaves to fd set */ it = _ctrl_slaves; while (it) { FD_SET(it->sock, rfds); *n = MAX(*n, it->sock); it = it->next; } } void ctrl_check_fds(fd_set * rfds, fd_set * wfds) { int ns, res, offs; struct sockaddr_un fsaun; socklen_t fromlen; _ctrl_slave_t *it; if (ctrlsock == 0) return; memset(&fsaun, 0, sizeof(struct sockaddr_un)); /* check if we got any connections on server socket */ if (FD_ISSET(ctrlsock, rfds)) { FD_CLR(ctrlsock, rfds); fromlen = sizeof(fsaun); ns = accept(ctrlsock, (struct sockaddr *) &fsaun, &fromlen); if (ns < 0) { perror("server: accept()"); exit(1); } _ctrl_slave_new(ns); return; } /* check if any of our slaves fds has data */ it = _ctrl_slaves; while (it) { if (FD_ISSET(it->sock, rfds)) { offs = strlen(it->linebuf); res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs, 0); FD_CLR(it->sock, rfds); /* linebuffer full let's disconnect slave */ if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' && it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n') { _ctrl_slave_disconnect(it->sock); break; } if (res > 0) { /* Check if we got full command line */ char *p; if ((p = strchr(it->linebuf, '\n')) == NULL) continue; /* iterate over string and check against escaped \n */ while (p) { /* Check if newline is escaped */ if (p > it->linebuf && *(p - 1) != '\\') break; p = strchr(p + 1, '\n'); } /* If we havent found an nonescaped \n we need more data */ if (p == NULL) continue; /* strip new linebuf and dispatch command */ *p = '\0'; _ctrl_dispatch_command(it); memset(it->linebuf, 0, CTRL_LINEBUF_SIZE); } else { /* Peer disconnected or socket error */ _ctrl_slave_disconnect(it->sock); break; } } it = it->next; } } #if HAVE_ICONV extern char g_codepage[16]; #endif int ctrl_send_command(const char *cmd, const char *arg) { FILE *fp; struct sockaddr_un saun; int s, len, index, ret; char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE]; char result[CTRL_RESULT_SIZE], c, *escaped; escaped = NULL; if (!_ctrl_is_slave) return -1; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("Error creating ctrl client socket: socket()"); exit(1); } memset(&saun, 0, sizeof(struct sockaddr_un)); saun.sun_family = AF_UNIX; strcpy(saun.sun_path, ctrlsock_name); len = sizeof(saun.sun_family) + strlen(saun.sun_path); if (connect(s, (struct sockaddr *) &saun, len) < 0) { perror("Error connecting to ctrl socket: connect()"); exit(1); } /* Bundle cmd and argument into string, convert to UTF-8 if needed */ snprintf(data, CTRL_LINEBUF_SIZE, "%s %s", cmd, arg); ret = utils_locale_to_utf8(data, strlen(data), tmp, CTRL_LINEBUF_SIZE - 1); if (ret != 0) goto bail_out; /* escape the utf-8 string */ escaped = utils_string_escape(tmp); if ((strlen(escaped) + 1) > CTRL_LINEBUF_SIZE - 1) goto bail_out; /* send escaped utf-8 command to master */ send(s, escaped, strlen(escaped), 0); send(s, "\n", 1, 0); /* read result from master */ fp = fdopen(s, "r"); index = 0; while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n') { result[index] = c; index++; } result[index - 1] = '\0'; if (strncmp(result, "ERROR ", 6) == 0) { if (sscanf(result, "ERROR %d", &ret) != 1) ret = -1; } bail_out: xfree(escaped); shutdown(s, SHUT_RDWR); close(s); return ret; } rdesktop-1.8.3/disk.c0000664000770100510440000010265712252340726013411 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Disk Redirection Copyright (C) Jeroen Meijer 2003-2008 Copyright 2003-2011 Peter Astrand for Cendio AB 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 3 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, see . */ #include "disk.h" #include #include #include #include /* open, close */ #include /* opendir, closedir, readdir */ #include #include /* errno */ #include #include #include /* ctime */ #if (defined(HAVE_DIRFD) || (HAVE_DECL_DIRFD == 1)) #define DIRFD(a) (dirfd(a)) #else #define DIRFD(a) ((a)->DIR_FD_MEMBER_NAME) #endif /* TODO: Fix mntent-handling for solaris * #include */ #if (defined(HAVE_MNTENT_H) && defined(HAVE_SETMNTENT)) #include #define MNTENT_PATH "/etc/mtab" #define USE_SETMNTENT #endif #ifdef HAVE_SYS_VFS_H #include #endif #ifdef HAVE_SYS_STATVFS_H #include #endif #ifdef HAVE_SYS_STATFS_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #include "rdesktop.h" #ifdef STAT_STATFS3_OSF1 #define STATFS_FN(path, buf) (statfs(path,buf,sizeof(buf))) #define STATFS_T statfs #define USE_STATFS #endif #ifdef STAT_STATVFS #define STATFS_FN(path, buf) (statvfs(path,buf)) #define STATFS_T statvfs #define USE_STATVFS #endif #ifdef STAT_STATVFS64 #define STATFS_FN(path, buf) (statvfs64(path,buf)) #define STATFS_T statvfs64 #define USE_STATVFS #endif #if (defined(STAT_STATFS2_FS_DATA) || defined(STAT_STATFS2_BSIZE) || defined(STAT_STATFS2_FSIZE)) #define STATFS_FN(path, buf) (statfs(path,buf)) #define STATFS_T statfs #define USE_STATFS #endif #ifdef STAT_STATFS4 #define STATFS_FN(path, buf) (statfs(path,buf,sizeof(buf),0)) #define STATFS_T statfs #define USE_STATFS #endif #if ((defined(USE_STATFS) && defined(HAVE_STRUCT_STATFS_F_NAMEMAX)) || (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_NAMEMAX))) #define F_NAMELEN(buf) ((buf).f_namemax) #endif #if ((defined(USE_STATFS) && defined(HAVE_STRUCT_STATFS_F_NAMELEN)) || (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_NAMELEN))) #define F_NAMELEN(buf) ((buf).f_namelen) #endif #ifndef F_NAMELEN #define F_NAMELEN(buf) (255) #endif /* Dummy statfs fallback */ #ifndef STATFS_T struct dummy_statfs_t { long f_bfree; long f_bsize; long f_bavail; long f_blocks; int f_namelen; int f_namemax; }; static int dummy_statfs(struct dummy_statfs_t *buf) { buf->f_blocks = 262144; buf->f_bfree = 131072; buf->f_bavail = 131072; buf->f_bsize = 512; buf->f_namelen = 255; buf->f_namemax = 255; return 0; } #define STATFS_T dummy_statfs_t #define STATFS_FN(path,buf) (dummy_statfs(buf)) #endif extern RDPDR_DEVICE g_rdpdr_device[]; FILEINFO g_fileinfo[MAX_OPEN_FILES]; RD_BOOL g_notify_stamp = False; typedef struct { char name[PATH_MAX]; char label[PATH_MAX]; unsigned long serial; char type[PATH_MAX]; } FsInfoType; static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p); static time_t get_create_time(struct stat *filestat) { time_t ret, ret1; ret = MIN(filestat->st_ctime, filestat->st_mtime); ret1 = MIN(ret, filestat->st_atime); if (ret1 != (time_t) 0) return ret1; return ret; } /* Convert seconds since 1970 to a filetime */ static void seconds_since_1970_to_filetime(time_t seconds, uint32 * high, uint32 * low) { unsigned long long ticks; ticks = (seconds + 11644473600LL) * 10000000; *low = (uint32) ticks; *high = (uint32) (ticks >> 32); } /* Convert seconds since 1970 back to filetime */ static time_t convert_1970_to_filetime(uint32 high, uint32 low) { unsigned long long ticks; time_t val; ticks = low + (((unsigned long long) high) << 32); ticks /= 10000000; ticks -= 11644473600LL; val = (time_t) ticks; return (val); } /* A wrapper for ftruncate which supports growing files, even if the native ftruncate doesn't. This is needed on Linux FAT filesystems, for example. */ static int ftruncate_growable(int fd, off_t length) { int ret; off_t pos; static const char zero = 0; /* Try the simple method first */ if ((ret = ftruncate(fd, length)) != -1) { return ret; } /* * Some kind of error. Perhaps we were trying to grow. Retry * in a safe way. */ /* Get current position */ if ((pos = lseek(fd, 0, SEEK_CUR)) == -1) { perror("lseek"); return -1; } /* Seek to new size */ if (lseek(fd, length, SEEK_SET) == -1) { perror("lseek"); return -1; } /* Write a zero */ if (write(fd, &zero, 1) == -1) { perror("write"); return -1; } /* Truncate. This shouldn't fail. */ if (ftruncate(fd, length) == -1) { perror("ftruncate"); return -1; } /* Restore position */ if (lseek(fd, pos, SEEK_SET) == -1) { perror("lseek"); return -1; } return 0; } /* Just like open(2), but if a open with O_EXCL fails, retry with GUARDED semantics. This might be necessary because some filesystems (such as NFS filesystems mounted from a unfsd server) doesn't support O_EXCL. GUARDED semantics are subject to race conditions, but we can live with that. */ static int open_weak_exclusive(const char *pathname, int flags, mode_t mode) { int ret; struct stat filestat; ret = open(pathname, flags, mode); if (ret != -1 || !(flags & O_EXCL)) { /* Success, or not using O_EXCL */ return ret; } /* An error occured, and we are using O_EXCL. In case the FS doesn't support O_EXCL, some kind of error will be returned. Unfortunately, we don't know which one. Linux 2.6.8 seems to return 524, but I cannot find a documented #define for this case. So, we'll return only on errors that we know aren't related to O_EXCL. */ switch (errno) { case EACCES: case EEXIST: case EINTR: case EISDIR: case ELOOP: case ENAMETOOLONG: case ENOENT: case ENOTDIR: return ret; } /* Retry with GUARDED semantics */ if (stat(pathname, &filestat) != -1) { /* File exists */ errno = EEXIST; return -1; } else { return open(pathname, flags & ~O_EXCL, mode); } } /* Enumeration of devices from rdesktop.c */ /* returns numer of units found and initialized. */ /* optarg looks like ':h=/mnt/floppy,b=/mnt/usbdevice1' */ /* when it arrives to this function. */ int disk_enum_devices(uint32 * id, char *optarg) { char *pos = optarg; char *pos2; int count = 0; /* skip the first colon */ optarg++; while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES) { pos2 = next_arg(optarg, '='); strncpy(g_rdpdr_device[*id].name, optarg, sizeof(g_rdpdr_device[*id].name) - 1); if (strlen(optarg) > (sizeof(g_rdpdr_device[*id].name) - 1)) fprintf(stderr, "share name %s truncated to %s\n", optarg, g_rdpdr_device[*id].name); g_rdpdr_device[*id].local_path = (char *) xmalloc(strlen(pos2) + 1); strcpy(g_rdpdr_device[*id].local_path, pos2); g_rdpdr_device[*id].device_type = DEVICE_TYPE_DISK; count++; (*id)++; optarg = pos; } return count; } /* Opens or creates a file or directory */ static RD_NTSTATUS disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle) { RD_NTHANDLE handle; DIR *dirp; int flags, mode; char path[PATH_MAX]; struct stat filestat; handle = 0; dirp = NULL; flags = 0; mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; if (filename && *filename && filename[strlen(filename) - 1] == '/') filename[strlen(filename) - 1] = 0; sprintf(path, "%s%s", g_rdpdr_device[device_id].local_path, filename ? filename : ""); /* Protect against mailicous servers: somelongpath/.. not allowed somelongpath/../b not allowed somelongpath/..b in principle ok, but currently not allowed somelongpath/b.. ok somelongpath/b..b ok somelongpath/b../c ok */ if (strstr(path, "/..")) { return RD_STATUS_ACCESS_DENIED; } switch (create_disposition) { case CREATE_ALWAYS: /* Delete existing file/link. */ unlink(path); flags |= O_CREAT; break; case CREATE_NEW: /* If the file already exists, then fail. */ flags |= O_CREAT | O_EXCL; break; case OPEN_ALWAYS: /* Create if not already exists. */ flags |= O_CREAT; break; case OPEN_EXISTING: /* Default behaviour */ break; case TRUNCATE_EXISTING: /* If the file does not exist, then fail. */ flags |= O_TRUNC; break; } /*printf("Open: \"%s\" flags: %X, accessmask: %X sharemode: %X create disp: %X\n", path, flags_and_attributes, accessmask, sharemode, create_disposition); */ /* Get information about file and set that flag ourselfs */ if ((stat(path, &filestat) == 0) && (S_ISDIR(filestat.st_mode))) { if (flags_and_attributes & FILE_NON_DIRECTORY_FILE) return RD_STATUS_FILE_IS_A_DIRECTORY; else flags_and_attributes |= FILE_DIRECTORY_FILE; } if (flags_and_attributes & FILE_DIRECTORY_FILE) { if (flags & O_CREAT) { mkdir(path, mode); } dirp = opendir(path); if (!dirp) { switch (errno) { case EACCES: return RD_STATUS_ACCESS_DENIED; case ENOENT: return RD_STATUS_NO_SUCH_FILE; default: perror("opendir"); return RD_STATUS_NO_SUCH_FILE; } } handle = DIRFD(dirp); } else { if (accessmask & GENERIC_ALL || (accessmask & GENERIC_READ && accessmask & GENERIC_WRITE)) { flags |= O_RDWR; } else if ((accessmask & GENERIC_WRITE) && !(accessmask & GENERIC_READ)) { flags |= O_WRONLY; } else { flags |= O_RDONLY; } handle = open_weak_exclusive(path, flags, mode); if (handle == -1) { switch (errno) { case EISDIR: return RD_STATUS_FILE_IS_A_DIRECTORY; case EACCES: return RD_STATUS_ACCESS_DENIED; case ENOENT: return RD_STATUS_NO_SUCH_FILE; case EEXIST: return RD_STATUS_OBJECT_NAME_COLLISION; default: perror("open"); return RD_STATUS_NO_SUCH_FILE; } } /* all read and writes of files should be non blocking */ if (fcntl(handle, F_SETFL, O_NONBLOCK) == -1) perror("fcntl"); } if (handle >= MAX_OPEN_FILES) { error("Maximum number of open files (%s) reached. Increase MAX_OPEN_FILES!\n", handle); exit(EX_SOFTWARE); } if (dirp) g_fileinfo[handle].pdir = dirp; else g_fileinfo[handle].pdir = NULL; g_fileinfo[handle].device_id = device_id; g_fileinfo[handle].flags_and_attributes = flags_and_attributes; g_fileinfo[handle].accessmask = accessmask; strncpy(g_fileinfo[handle].path, path, PATH_MAX - 1); g_fileinfo[handle].delete_on_close = False; if (accessmask & GENERIC_ALL || accessmask & GENERIC_WRITE) g_notify_stamp = True; *phandle = handle; return RD_STATUS_SUCCESS; } static RD_NTSTATUS disk_close(RD_NTHANDLE handle) { struct fileinfo *pfinfo; pfinfo = &(g_fileinfo[handle]); if (pfinfo->accessmask & GENERIC_ALL || pfinfo->accessmask & GENERIC_WRITE) g_notify_stamp = True; rdpdr_abort_io(handle, 0, RD_STATUS_CANCELLED); if (pfinfo->pdir) { if (closedir(pfinfo->pdir) < 0) { perror("closedir"); return RD_STATUS_INVALID_HANDLE; } if (pfinfo->delete_on_close) if (rmdir(pfinfo->path) < 0) { perror(pfinfo->path); return RD_STATUS_ACCESS_DENIED; } pfinfo->delete_on_close = False; } else { if (close(handle) < 0) { perror("close"); return RD_STATUS_INVALID_HANDLE; } if (pfinfo->delete_on_close) if (unlink(pfinfo->path) < 0) { perror(pfinfo->path); return RD_STATUS_ACCESS_DENIED; } pfinfo->delete_on_close = False; } return RD_STATUS_SUCCESS; } static RD_NTSTATUS disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { int n; #if 0 /* browsing dir ???? */ /* each request is 24 bytes */ if (g_fileinfo[handle].flags_and_attributes & FILE_DIRECTORY_FILE) { *result = 0; return STATUS_SUCCESS; } #endif lseek(handle, offset, SEEK_SET); n = read(handle, data, length); if (n < 0) { *result = 0; switch (errno) { case EISDIR: /* Implement 24 Byte directory read ?? with STATUS_NOT_IMPLEMENTED server doesn't read again */ /* return STATUS_FILE_IS_A_DIRECTORY; */ return RD_STATUS_NOT_IMPLEMENTED; default: perror("read"); return RD_STATUS_INVALID_PARAMETER; } } *result = n; return RD_STATUS_SUCCESS; } static RD_NTSTATUS disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { int n; lseek(handle, offset, SEEK_SET); n = write(handle, data, length); if (n < 0) { perror("write"); *result = 0; switch (errno) { case ENOSPC: return RD_STATUS_DISK_FULL; default: return RD_STATUS_ACCESS_DENIED; } } *result = n; return RD_STATUS_SUCCESS; } RD_NTSTATUS disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out) { uint32 file_attributes, ft_high, ft_low; struct stat filestat; char *path, *filename; path = g_fileinfo[handle].path; /* Get information about file */ if (fstat(handle, &filestat) != 0) { perror("stat"); out_uint8(out, 0); return RD_STATUS_ACCESS_DENIED; } /* Set file attributes */ file_attributes = 0; if (S_ISDIR(filestat.st_mode)) file_attributes |= FILE_ATTRIBUTE_DIRECTORY; filename = 1 + strrchr(path, '/'); if (filename && filename[0] == '.') file_attributes |= FILE_ATTRIBUTE_HIDDEN; if (!file_attributes) file_attributes |= FILE_ATTRIBUTE_NORMAL; if (!(filestat.st_mode & S_IWUSR)) file_attributes |= FILE_ATTRIBUTE_READONLY; /* Return requested data */ switch (info_class) { case FileBasicInformation: seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low); out_uint32_le(out, ft_low); /* create_access_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_access_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_write_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_change_time */ out_uint32_le(out, ft_high); out_uint32_le(out, file_attributes); break; case FileStandardInformation: out_uint32_le(out, filestat.st_size); /* Allocation size */ out_uint32_le(out, 0); out_uint32_le(out, filestat.st_size); /* End of file */ out_uint32_le(out, 0); out_uint32_le(out, filestat.st_nlink); /* Number of links */ out_uint8(out, 0); /* Delete pending */ out_uint8(out, S_ISDIR(filestat.st_mode) ? 1 : 0); /* Directory */ break; case FileObjectIdInformation: out_uint32_le(out, file_attributes); /* File Attributes */ out_uint32_le(out, 0); /* Reparse Tag */ break; default: unimpl("IRP Query (File) Information class: 0x%x\n", info_class); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; } RD_NTSTATUS disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out) { uint32 length, file_attributes, ft_high, ft_low; char *newname, fullpath[PATH_MAX]; struct fileinfo *pfinfo; int mode; struct stat filestat; time_t write_time, change_time, access_time, mod_time; struct utimbuf tvs; struct STATFS_T stat_fs; pfinfo = &(g_fileinfo[handle]); g_notify_stamp = True; newname = NULL; switch (info_class) { case FileBasicInformation: write_time = change_time = access_time = 0; in_uint8s(in, 4); /* Handle of root dir? */ in_uint8s(in, 24); /* unknown */ /* CreationTime */ in_uint32_le(in, ft_low); in_uint32_le(in, ft_high); /* AccessTime */ in_uint32_le(in, ft_low); in_uint32_le(in, ft_high); if (ft_low || ft_high) access_time = convert_1970_to_filetime(ft_high, ft_low); /* WriteTime */ in_uint32_le(in, ft_low); in_uint32_le(in, ft_high); if (ft_low || ft_high) write_time = convert_1970_to_filetime(ft_high, ft_low); /* ChangeTime */ in_uint32_le(in, ft_low); in_uint32_le(in, ft_high); if (ft_low || ft_high) change_time = convert_1970_to_filetime(ft_high, ft_low); in_uint32_le(in, file_attributes); if (fstat(handle, &filestat)) return RD_STATUS_ACCESS_DENIED; tvs.modtime = filestat.st_mtime; tvs.actime = filestat.st_atime; if (access_time) tvs.actime = access_time; if (write_time || change_time) mod_time = MIN(write_time, change_time); else mod_time = write_time ? write_time : change_time; if (mod_time) tvs.modtime = mod_time; if (access_time || write_time || change_time) { #if WITH_DEBUG_RDP5 printf("FileBasicInformation access time %s", ctime(&tvs.actime)); printf("FileBasicInformation modification time %s", ctime(&tvs.modtime)); #endif if (utime(pfinfo->path, &tvs) && errno != EPERM) return RD_STATUS_ACCESS_DENIED; } if (!file_attributes) break; /* not valid */ mode = filestat.st_mode; if (file_attributes & FILE_ATTRIBUTE_READONLY) mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); else mode |= S_IWUSR; mode &= 0777; #if WITH_DEBUG_RDP5 printf("FileBasicInformation set access mode 0%o", mode); #endif if (fchmod(handle, mode)) return RD_STATUS_ACCESS_DENIED; break; case FileRenameInformation: in_uint8s(in, 4); /* Handle of root dir? */ in_uint8s(in, 0x1a); /* unknown */ in_uint32_le(in, length); if (length && (length / 2) >= 256) return RD_STATUS_INVALID_PARAMETER; rdp_in_unistr(in, length, &newname, &length); if (newname == NULL) return RD_STATUS_INVALID_PARAMETER; convert_to_unix_filename(newname); sprintf(fullpath, "%s%s", g_rdpdr_device[pfinfo->device_id].local_path, newname); free(newname); if (rename(pfinfo->path, fullpath) != 0) { perror("rename"); return RD_STATUS_ACCESS_DENIED; } break; case FileDispositionInformation: /* As far as I understand it, the correct thing to do here is to *schedule* a delete, so it will be deleted when the file is closed. Subsequent FileDispositionInformation requests with DeleteFile set to FALSE should unschedule the delete. See http://www.osronline.com/article.cfm?article=245. */ /* FileDispositionInformation always sets delete_on_close to true. "STREAM in" includes Length(4bytes) , Padding(24bytes) and SetBuffer(zero byte). Length is always set to zero. [MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx - 2.2.3.3.9 Server Drive Set Information Request */ in_uint8s(in, 4); /* length of SetBuffer */ in_uint8s(in, 24); /* padding */ if ((pfinfo->accessmask & (FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED))) { /* if file exists in directory , necessary to return RD_STATUS_DIRECTORY_NOT_EMPTY with win2008 [MS-RDPEFS] http://msdn.microsoft.com/en-us/library/cc241305%28PROT.10%29.aspx - 2.2.3.3.9 Server Drive Set Information Request - 2.2.3.4.9 Client Drive Set Information Response [MS-FSCC] http://msdn.microsoft.com/en-us/library/cc231987%28PROT.10%29.aspx - 2.4.11 FileDispositionInformation [FSBO] http://msdn.microsoft.com/en-us/library/cc246487%28PROT.13%29.aspx - 4.3.2 Set Delete-on-close using FileDispositionInformation Information Class (IRP_MJ_SET_INFORMATION) */ if (pfinfo->pdir) { DIR *dp = opendir(pfinfo->path); struct dirent *dir; while ((dir = readdir(dp)) != NULL) { if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0) { closedir(dp); return RD_STATUS_DIRECTORY_NOT_EMPTY; } } closedir(dp); } pfinfo->delete_on_close = True; } break; case FileAllocationInformation: /* Fall through to FileEndOfFileInformation, which uses ftrunc. This is like Samba with "strict allocation = false", and means that we won't detect out-of-quota errors, for example. */ case FileEndOfFileInformation: in_uint8s(in, 28); /* unknown */ in_uint32_le(in, length); /* file size */ /* prevents start of writing if not enough space left on device */ if (STATFS_FN(pfinfo->path, &stat_fs) == 0) if (stat_fs.f_bfree * stat_fs.f_bsize < length) return RD_STATUS_DISK_FULL; if (ftruncate_growable(handle, length) != 0) { return RD_STATUS_DISK_FULL; } break; default: unimpl("IRP Set File Information class: 0x%x\n", info_class); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; } RD_NTSTATUS disk_check_notify(RD_NTHANDLE handle) { struct fileinfo *pfinfo; RD_NTSTATUS status = RD_STATUS_PENDING; NOTIFY notify; pfinfo = &(g_fileinfo[handle]); if (!pfinfo->pdir) return RD_STATUS_INVALID_DEVICE_REQUEST; status = NotifyInfo(handle, pfinfo->info_class, ¬ify); if (status != RD_STATUS_PENDING) return status; if (memcmp(&pfinfo->notify, ¬ify, sizeof(NOTIFY))) { /*printf("disk_check_notify found changed event\n"); */ memcpy(&pfinfo->notify, ¬ify, sizeof(NOTIFY)); status = RD_STATUS_NOTIFY_ENUM_DIR; } return status; } RD_NTSTATUS disk_create_notify(RD_NTHANDLE handle, uint32 info_class) { struct fileinfo *pfinfo; RD_NTSTATUS ret = RD_STATUS_PENDING; /* printf("start disk_create_notify info_class %X\n", info_class); */ pfinfo = &(g_fileinfo[handle]); pfinfo->info_class = info_class; ret = NotifyInfo(handle, info_class, &pfinfo->notify); if (info_class & 0x1000) { /* ???? */ if (ret == RD_STATUS_PENDING) return RD_STATUS_SUCCESS; } /* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */ return ret; } static RD_NTSTATUS NotifyInfo(RD_NTHANDLE handle, uint32 info_class, NOTIFY * p) { struct fileinfo *pfinfo; struct stat filestat; struct dirent *dp; char *fullname; DIR *dpr; pfinfo = &(g_fileinfo[handle]); if (fstat(handle, &filestat) < 0) { perror("NotifyInfo"); return RD_STATUS_ACCESS_DENIED; } p->modify_time = filestat.st_mtime; p->status_time = filestat.st_ctime; p->num_entries = 0; p->total_time = 0; dpr = opendir(pfinfo->path); if (!dpr) { perror("NotifyInfo"); return RD_STATUS_ACCESS_DENIED; } while ((dp = readdir(dpr))) { if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; p->num_entries++; fullname = (char *) xmalloc(strlen(pfinfo->path) + strlen(dp->d_name) + 2); sprintf(fullname, "%s/%s", pfinfo->path, dp->d_name); if (!stat(fullname, &filestat)) { p->total_time += (filestat.st_mtime + filestat.st_ctime); } xfree(fullname); } closedir(dpr); return RD_STATUS_PENDING; } static FsInfoType * FsVolumeInfo(char *fpath) { static FsInfoType info; #ifdef USE_SETMNTENT FILE *fdfs; struct mntent *e; #endif /* initialize */ memset(&info, 0, sizeof(info)); strcpy(info.label, "RDESKTOP"); strcpy(info.type, "RDPFS"); #ifdef USE_SETMNTENT fdfs = setmntent(MNTENT_PATH, "r"); if (!fdfs) return &info; while ((e = getmntent(fdfs))) { if (str_startswith(e->mnt_dir, fpath)) { strcpy(info.type, e->mnt_type); strcpy(info.name, e->mnt_fsname); if (strstr(e->mnt_opts, "vfat") || strstr(e->mnt_opts, "iso9660")) { int fd = open(e->mnt_fsname, O_RDONLY); if (fd >= 0) { unsigned char buf[512]; memset(buf, 0, sizeof(buf)); if (strstr(e->mnt_opts, "vfat")) /*FAT*/ { strcpy(info.type, "vfat"); read(fd, buf, sizeof(buf)); info.serial = (buf[42] << 24) + (buf[41] << 16) + (buf[40] << 8) + buf[39]; strncpy(info.label, (char *) buf + 43, 10); info.label[10] = '\0'; } else if (lseek(fd, 32767, SEEK_SET) >= 0) /* ISO9660 */ { read(fd, buf, sizeof(buf)); strncpy(info.label, (char *) buf + 41, 32); info.label[32] = '\0'; /* info.Serial = (buf[128]<<24)+(buf[127]<<16)+(buf[126]<<8)+buf[125]; */ } close(fd); } } } } endmntent(fdfs); #else /* initialize */ memset(&info, 0, sizeof(info)); strcpy(info.label, "RDESKTOP"); strcpy(info.type, "RDPFS"); #endif return &info; } RD_NTSTATUS disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out) { struct STATFS_T stat_fs; struct fileinfo *pfinfo; FsInfoType *fsinfo; pfinfo = &(g_fileinfo[handle]); if (STATFS_FN(pfinfo->path, &stat_fs) != 0) { perror("statfs"); return RD_STATUS_ACCESS_DENIED; } fsinfo = FsVolumeInfo(pfinfo->path); switch (info_class) { case FileFsVolumeInformation: out_uint32_le(out, 0); /* volume creation time low */ out_uint32_le(out, 0); /* volume creation time high */ out_uint32_le(out, fsinfo->serial); /* serial */ out_uint32_le(out, 2 * strlen(fsinfo->label)); /* length of string */ out_uint8(out, 0); /* support objects? */ rdp_out_unistr(out, fsinfo->label, 2 * strlen(fsinfo->label) - 2); break; case FileFsSizeInformation: out_uint32_le(out, stat_fs.f_blocks); /* Total allocation units low */ out_uint32_le(out, 0); /* Total allocation high units */ out_uint32_le(out, stat_fs.f_bfree); /* Available allocation units */ out_uint32_le(out, 0); /* Available allowcation units */ out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */ out_uint32_le(out, 0x200); /* Bytes per sector */ break; case FileFsFullSizeInformation: out_uint32_le(out, stat_fs.f_blocks); /* Total allocation units low */ out_uint32_le(out, 0); /* Total allocation units high */ out_uint32_le(out, stat_fs.f_bavail); /* Caller allocation units low */ out_uint32_le(out, 0); /* Caller allocation units high */ out_uint32_le(out, stat_fs.f_bfree); /* Available allocation units */ out_uint32_le(out, 0); /* Available allowcation units */ out_uint32_le(out, stat_fs.f_bsize / 0x200); /* Sectors per allocation unit */ out_uint32_le(out, 0x200); /* Bytes per sector */ break; case FileFsAttributeInformation: out_uint32_le(out, FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED); /* fs attributes */ out_uint32_le(out, F_NAMELEN(stat_fs)); /* max length of filename */ out_uint32_le(out, 2 * strlen(fsinfo->type)); /* length of fs_type */ rdp_out_unistr(out, fsinfo->type, 2 * strlen(fsinfo->type) - 2); break; case FileFsLabelInformation: case FileFsDeviceInformation: case FileFsControlInformation: case FileFsObjectIdInformation: case FileFsMaximumInformation: default: unimpl("IRP Query Volume Information class: 0x%x\n", info_class); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; } RD_NTSTATUS disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out) { uint32 file_attributes, ft_low, ft_high; char *dirname, fullpath[PATH_MAX]; DIR *pdir; struct dirent *pdirent; struct stat filestat; struct fileinfo *pfinfo; pfinfo = &(g_fileinfo[handle]); pdir = pfinfo->pdir; dirname = pfinfo->path; file_attributes = 0; switch (info_class) { case FileBothDirectoryInformation: case FileDirectoryInformation: case FileFullDirectoryInformation: case FileNamesInformation: /* If a search pattern is received, remember this pattern, and restart search */ if (pattern != NULL && pattern[0] != 0) { strncpy(pfinfo->pattern, 1 + strrchr(pattern, '/'), PATH_MAX - 1); rewinddir(pdir); } /* find next dirent matching pattern */ pdirent = readdir(pdir); while (pdirent && fnmatch(pfinfo->pattern, pdirent->d_name, 0) != 0) pdirent = readdir(pdir); if (pdirent == NULL) return RD_STATUS_NO_MORE_FILES; /* Get information for directory entry */ sprintf(fullpath, "%s/%s", dirname, pdirent->d_name); if (stat(fullpath, &filestat)) { switch (errno) { case ENOENT: case ELOOP: case EACCES: /* These are non-fatal errors. */ memset(&filestat, 0, sizeof(filestat)); break; default: /* Fatal error. By returning STATUS_NO_SUCH_FILE, the directory list operation will be aborted */ perror(fullpath); out_uint8(out, 0); return RD_STATUS_NO_SUCH_FILE; } } if (S_ISDIR(filestat.st_mode)) file_attributes |= FILE_ATTRIBUTE_DIRECTORY; if (pdirent->d_name[0] == '.') file_attributes |= FILE_ATTRIBUTE_HIDDEN; if (!file_attributes) file_attributes |= FILE_ATTRIBUTE_NORMAL; if (!(filestat.st_mode & S_IWUSR)) file_attributes |= FILE_ATTRIBUTE_READONLY; /* Return requested information */ out_uint32_le(out, 0); /* NextEntryOffset */ out_uint32_le(out, 0); /* FileIndex zero */ break; default: unimpl("IRP Query Directory sub: 0x%x\n", info_class); return RD_STATUS_INVALID_PARAMETER; } switch (info_class) { case FileBothDirectoryInformation: seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low); out_uint32_le(out, ft_low); /* create time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_access_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_write_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* change_write_time */ out_uint32_le(out, ft_high); out_uint32_le(out, filestat.st_size); /* filesize low */ out_uint32_le(out, 0); /* filesize high */ out_uint32_le(out, filestat.st_size); /* filesize low */ out_uint32_le(out, 0); /* filesize high */ out_uint32_le(out, file_attributes); /* FileAttributes */ out_uint32_le(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ out_uint32_le(out, 0); /* EaSize */ out_uint8(out, 0); /* ShortNameLength */ /* this should be correct according to MS-FSCC specification but it only works when commented out... */ /* out_uint8(out, 0); *//* Reserved/Padding */ out_uint8s(out, 2 * 12); /* ShortName (8.3 name) */ rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); break; case FileDirectoryInformation: seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low); out_uint32_le(out, ft_low); /* create time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_access_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_write_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* change_write_time */ out_uint32_le(out, ft_high); out_uint32_le(out, filestat.st_size); /* filesize low */ out_uint32_le(out, 0); /* filesize high */ out_uint32_le(out, filestat.st_size); /* filesize low */ out_uint32_le(out, 0); /* filesize high */ out_uint32_le(out, file_attributes); out_uint32_le(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); break; case FileFullDirectoryInformation: seconds_since_1970_to_filetime(get_create_time(&filestat), &ft_high, &ft_low); out_uint32_le(out, ft_low); /* create time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_atime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_access_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_mtime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* last_write_time */ out_uint32_le(out, ft_high); seconds_since_1970_to_filetime(filestat.st_ctime, &ft_high, &ft_low); out_uint32_le(out, ft_low); /* change_write_time */ out_uint32_le(out, ft_high); out_uint32_le(out, filestat.st_size); /* filesize low */ out_uint32_le(out, 0); /* filesize high */ out_uint32_le(out, filestat.st_size); /* filesize low */ out_uint32_le(out, 0); /* filesize high */ out_uint32_le(out, file_attributes); out_uint32_le(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ out_uint32_le(out, 0); /* EaSize */ rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); break; case FileNamesInformation: out_uint32_le(out, 2 * strlen(pdirent->d_name) + 2); /* unicode length */ rdp_out_unistr(out, pdirent->d_name, 2 * strlen(pdirent->d_name)); break; default: unimpl("IRP Query Directory sub: 0x%x\n", info_class); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; } static RD_NTSTATUS disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) { if (((request >> 16) != 20) || ((request >> 16) != 9)) return RD_STATUS_INVALID_PARAMETER; /* extract operation */ request >>= 2; request &= 0xfff; printf("DISK IOCTL %d\n", request); switch (request) { case 25: /* ? */ case 42: /* ? */ default: unimpl("DISK IOCTL %d\n", request); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; } DEVICE_FNS disk_fns = { disk_create, disk_close, disk_read, disk_write, disk_device_control /* device_control */ }; rdesktop-1.8.3/ewmhints.c0000664000770100510440000003461312216606214014306 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Support functions for Extended Window Manager Hints, http://www.freedesktop.org/wiki/Standards_2fwm_2dspec Copyright 2005-2011 Peter Astrand for Cendio AB Copyright 2007 Pierre Ossman for Cendio AB 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 3 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, see . */ #include #include #include #include "rdesktop.h" #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ #define _NET_WM_STATE_ADD 1 /* add/set property */ #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ extern Display *g_display; static Atom g_net_wm_state_maximized_vert_atom, g_net_wm_state_maximized_horz_atom, g_net_wm_state_hidden_atom, g_net_wm_name_atom, g_utf8_string_atom, g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom, g_net_wm_state_modal_atom, g_net_wm_icon_atom, g_net_wm_state_above_atom; Atom g_net_wm_state_atom, g_net_wm_desktop_atom; /* Get window property value (32 bit format) Returns zero on success, -1 on error */ static int get_property_value(Window wnd, char *propname, long max_length, unsigned long *nitems_return, unsigned char **prop_return, int nowarn) { int result; Atom property; Atom actual_type_return; int actual_format_return; unsigned long bytes_after_return; property = XInternAtom(g_display, propname, True); if (property == None) { fprintf(stderr, "Atom %s does not exist\n", propname); return (-1); } result = XGetWindowProperty(g_display, wnd, property, 0, /* long_offset */ max_length, /* long_length */ False, /* delete */ AnyPropertyType, /* req_type */ &actual_type_return, &actual_format_return, nitems_return, &bytes_after_return, prop_return); if (result != Success) { fprintf(stderr, "XGetWindowProperty failed\n"); return (-1); } if (actual_type_return == None || actual_format_return == 0) { if (!nowarn) fprintf(stderr, "Window is missing property %s\n", propname); return (-1); } if (bytes_after_return) { fprintf(stderr, "%s is too big for me\n", propname); return (-1); } if (actual_format_return != 32) { fprintf(stderr, "%s has bad format\n", propname); return (-1); } return (0); } /* Get current desktop number Returns -1 on error */ static int get_current_desktop(void) { unsigned long nitems_return; unsigned char *prop_return; int current_desktop; if (get_property_value (DefaultRootWindow(g_display), "_NET_CURRENT_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0) return (-1); if (nitems_return != 1) { fprintf(stderr, "_NET_CURRENT_DESKTOP has bad length\n"); return (-1); } current_desktop = *prop_return; XFree(prop_return); return current_desktop; } /* Get workarea geometry Returns zero on success, -1 on error */ int get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height) { int current_desktop; unsigned long nitems_return; unsigned char *prop_return; long *return_words; const uint32 net_workarea_x_offset = 0; const uint32 net_workarea_y_offset = 1; const uint32 net_workarea_width_offset = 2; const uint32 net_workarea_height_offset = 3; const uint32 max_prop_length = 32 * 4; /* Max 32 desktops */ if (get_property_value (DefaultRootWindow(g_display), "_NET_WORKAREA", max_prop_length, &nitems_return, &prop_return, 0) < 0) return (-1); if (nitems_return % 4) { fprintf(stderr, "_NET_WORKAREA has odd length\n"); return (-1); } current_desktop = get_current_desktop(); if (current_desktop < 0) return -1; return_words = (long *) prop_return; *x = return_words[current_desktop * 4 + net_workarea_x_offset]; *y = return_words[current_desktop * 4 + net_workarea_y_offset]; *width = return_words[current_desktop * 4 + net_workarea_width_offset]; *height = return_words[current_desktop * 4 + net_workarea_height_offset]; XFree(prop_return); return (0); } void ewmh_init() { /* FIXME: Use XInternAtoms */ g_net_wm_state_maximized_vert_atom = XInternAtom(g_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); g_net_wm_state_maximized_horz_atom = XInternAtom(g_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); g_net_wm_state_hidden_atom = XInternAtom(g_display, "_NET_WM_STATE_HIDDEN", False); g_net_wm_state_skip_taskbar_atom = XInternAtom(g_display, "_NET_WM_STATE_SKIP_TASKBAR", False); g_net_wm_state_skip_pager_atom = XInternAtom(g_display, "_NET_WM_STATE_SKIP_PAGER", False); g_net_wm_state_modal_atom = XInternAtom(g_display, "_NET_WM_STATE_MODAL", False); g_net_wm_state_above_atom = XInternAtom(g_display, "_NET_WM_STATE_ABOVE", False); g_net_wm_state_atom = XInternAtom(g_display, "_NET_WM_STATE", False); g_net_wm_desktop_atom = XInternAtom(g_display, "_NET_WM_DESKTOP", False); g_net_wm_name_atom = XInternAtom(g_display, "_NET_WM_NAME", False); g_net_wm_icon_atom = XInternAtom(g_display, "_NET_WM_ICON", False); g_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False); } /* Get the window state: normal/minimized/maximized. */ #ifndef MAKE_PROTO int ewmh_get_window_state(Window w) { unsigned long nitems_return; unsigned char *prop_return; unsigned long *return_words; unsigned long item; RD_BOOL maximized_vert, maximized_horz, hidden; maximized_vert = maximized_horz = hidden = False; if (get_property_value(w, "_NET_WM_STATE", 64, &nitems_return, &prop_return, 0) < 0) return SEAMLESSRDP_NORMAL; return_words = (unsigned long *) prop_return; for (item = 0; item < nitems_return; item++) { if (return_words[item] == g_net_wm_state_maximized_vert_atom) maximized_vert = True; if (return_words[item] == g_net_wm_state_maximized_horz_atom) maximized_horz = True; if (return_words[item] == g_net_wm_state_hidden_atom) hidden = True; } XFree(prop_return); /* In EWMH, HIDDEN overrides MAXIMIZED_VERT/MAXIMIZED_HORZ */ if (hidden) return SEAMLESSRDP_MINIMIZED; else if (maximized_vert && maximized_horz) return SEAMLESSRDP_MAXIMIZED; else return SEAMLESSRDP_NORMAL; } static int ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2) { Status status; XEvent xevent; int result; unsigned long nitems; unsigned char *props; uint32 state = WithdrawnState; /* The spec states that the window manager must respect any _NET_WM_STATE attributes on a withdrawn window. In order words, we modify the attributes directly for withdrawn windows and ask the WM to do it for active windows. */ result = get_property_value(wnd, "WM_STATE", 64, &nitems, &props, 1); if ((result >= 0) && nitems) { state = *(uint32 *) props; XFree(props); } if (state == WithdrawnState) { if (add) { Atom atoms[2]; atoms[0] = atom1; nitems = 1; if (atom2) { atoms[1] = atom2; nitems = 2; } XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM, 32, PropModeAppend, (unsigned char *) atoms, nitems); } else { Atom *atoms; int i; if (get_property_value(wnd, "_NET_WM_STATE", 64, &nitems, &props, 1) < 0) return 0; atoms = (Atom *) props; for (i = 0; i < nitems; i++) { if ((atoms[i] == atom1) || (atom2 && (atoms[i] == atom2))) { if (i != (nitems - 1)) memmove(&atoms[i], &atoms[i + 1], sizeof(Atom) * (nitems - i - 1)); nitems--; i--; } } XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *) atoms, nitems); XFree(props); } return 0; } xevent.type = ClientMessage; xevent.xclient.window = wnd; xevent.xclient.message_type = g_net_wm_state_atom; xevent.xclient.format = 32; if (add) xevent.xclient.data.l[0] = _NET_WM_STATE_ADD; else xevent.xclient.data.l[0] = _NET_WM_STATE_REMOVE; xevent.xclient.data.l[1] = atom1; xevent.xclient.data.l[2] = atom2; xevent.xclient.data.l[3] = 0; xevent.xclient.data.l[4] = 0; status = XSendEvent(g_display, DefaultRootWindow(g_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xevent); if (!status) return -1; return 0; } /* Set the window state: normal/minimized/maximized. Returns -1 on failure. */ int ewmh_change_state(Window wnd, int state) { /* * Deal with the max atoms */ if (state == SEAMLESSRDP_MAXIMIZED) { if (ewmh_modify_state (wnd, 1, g_net_wm_state_maximized_vert_atom, g_net_wm_state_maximized_horz_atom) < 0) return -1; } else { if (ewmh_modify_state (wnd, 0, g_net_wm_state_maximized_vert_atom, g_net_wm_state_maximized_horz_atom) < 0) return -1; } return 0; } int ewmh_get_window_desktop(Window wnd) { unsigned long nitems_return; unsigned char *prop_return; int desktop; if (get_property_value(wnd, "_NET_WM_DESKTOP", 1, &nitems_return, &prop_return, 0) < 0) return (-1); if (nitems_return != 1) { fprintf(stderr, "_NET_WM_DESKTOP has bad length\n"); return (-1); } desktop = *prop_return; XFree(prop_return); return desktop; } int ewmh_move_to_desktop(Window wnd, unsigned int desktop) { Status status; XEvent xevent; xevent.type = ClientMessage; xevent.xclient.window = wnd; xevent.xclient.message_type = g_net_wm_desktop_atom; xevent.xclient.format = 32; xevent.xclient.data.l[0] = desktop; xevent.xclient.data.l[1] = 0; xevent.xclient.data.l[2] = 0; xevent.xclient.data.l[3] = 0; xevent.xclient.data.l[4] = 0; status = XSendEvent(g_display, DefaultRootWindow(g_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xevent); if (!status) return -1; return 0; } void ewmh_set_wm_name(Window wnd, const char *title) { int len; len = strlen(title); XChangeProperty(g_display, wnd, g_net_wm_name_atom, g_utf8_string_atom, 8, PropModeReplace, (unsigned char *) title, len); } int ewmh_set_window_popup(Window wnd) { if (ewmh_modify_state (wnd, 1, g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom) < 0) return -1; return 0; } int ewmh_set_window_modal(Window wnd) { if (ewmh_modify_state(wnd, 1, g_net_wm_state_modal_atom, 0) < 0) return -1; return 0; } void ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data) { unsigned long nitems, i; unsigned char *props; unsigned long *cur_set, *new_set; unsigned long *icon; cur_set = NULL; new_set = NULL; if (get_property_value(wnd, "_NET_WM_ICON", 10000, &nitems, &props, 1) >= 0) { cur_set = (unsigned long *) props; for (i = 0; i < nitems;) { if (cur_set[i] == width && cur_set[i + 1] == height) break; i += 2 + cur_set[i] * cur_set[i + 1]; } if (i != nitems) icon = cur_set + i; else { new_set = xmalloc((nitems + width * height + 2) * sizeof(unsigned long)); memcpy(new_set, cur_set, nitems * sizeof(unsigned long)); icon = new_set + nitems; nitems += width * height + 2; } } else { new_set = xmalloc((width * height + 2) * sizeof(unsigned long)); icon = new_set; nitems = width * height + 2; } icon[0] = width; icon[1] = height; /* Convert RGBA -> ARGB */ for (i = 0; i < width * height; i++) { icon[i + 2] = rgba_data[i * 4 + 3] << 24 | ((rgba_data[i * 4 + 0] << 16) & 0x00FF0000) | ((rgba_data[i * 4 + 1] << 8) & 0x0000FF00) | ((rgba_data[i * 4 + 2] << 0) & 0x000000FF); } XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) (new_set ? new_set : cur_set), nitems); if (cur_set) XFree(cur_set); if (new_set) xfree(new_set); } void ewmh_del_icon(Window wnd, int width, int height) { unsigned long nitems, i, icon_size; unsigned char *props; unsigned long *cur_set, *new_set; cur_set = NULL; new_set = NULL; if (get_property_value(wnd, "_NET_WM_ICON", 10000, &nitems, &props, 1) < 0) return; cur_set = (unsigned long *) props; for (i = 0; i < nitems;) { if (cur_set[i] == width && cur_set[i + 1] == height) break; i += 2 + cur_set[i] * cur_set[i + 1]; } if (i == nitems) goto out; icon_size = width * height + 2; new_set = xmalloc((nitems - icon_size) * sizeof(unsigned long)); if (i != 0) memcpy(new_set, cur_set, i * sizeof(unsigned long)); if (i != nitems - icon_size) memcpy(new_set + i, cur_set + i + icon_size, (nitems - (i + icon_size)) * sizeof(unsigned long)); nitems -= icon_size; XChangeProperty(g_display, wnd, g_net_wm_icon_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) new_set, nitems); xfree(new_set); out: XFree(cur_set); } int ewmh_set_window_above(Window wnd) { if (ewmh_modify_state(wnd, 1, g_net_wm_state_above_atom, 0) < 0) return -1; return 0; } RD_BOOL ewmh_is_window_above(Window w) { unsigned long nitems_return; unsigned char *prop_return; unsigned long *return_words; unsigned long item; RD_BOOL above; above = False; if (get_property_value(w, "_NET_WM_STATE", 64, &nitems_return, &prop_return, 0) < 0) return False; return_words = (unsigned long *) prop_return; for (item = 0; item < nitems_return; item++) { if (return_words[item] == g_net_wm_state_above_atom) above = True; } XFree(prop_return); return above; } #endif /* MAKE_PROTO */ #if 0 /* FIXME: _NET_MOVERESIZE_WINDOW is for pagers, not for applications. We should implement _NET_WM_MOVERESIZE instead */ int ewmh_net_moveresize_window(Window wnd, int x, int y, int width, int height) { Status status; XEvent xevent; Atom moveresize; moveresize = XInternAtom(g_display, "_NET_MOVERESIZE_WINDOW", False); if (!moveresize) { return -1; } xevent.type = ClientMessage; xevent.xclient.window = wnd; xevent.xclient.message_type = moveresize; xevent.xclient.format = 32; xevent.xclient.data.l[0] = StaticGravity | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11); xevent.xclient.data.l[1] = x; xevent.xclient.data.l[2] = y; xevent.xclient.data.l[3] = width; xevent.xclient.data.l[4] = height; status = XSendEvent(g_display, DefaultRootWindow(g_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xevent); if (!status) return -1; return 0; } #endif rdesktop-1.8.3/iso.c0000664000770100510440000001751712336664005013253 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - ISO layer Copyright (C) Matthew Chapman 1999-2008 Copyright 2005-2011 Peter Astrand for Cendio AB Copyright 2012 Henrik Andersson for Cendio AB 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 3 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, see . */ #include "rdesktop.h" extern RD_BOOL g_encryption; extern RD_BOOL g_encryption_initial; extern RDP_VERSION g_rdp_version; extern RD_BOOL g_use_password_as_pin; static RD_BOOL g_negotiate_rdp_protocol = True; extern char *g_sc_csp_name; extern char *g_sc_reader_name; extern char *g_sc_card_name; extern char *g_sc_container_name; /* Send a self-contained ISO PDU */ static void iso_send_msg(uint8 code) { STREAM s; s = tcp_init(11); out_uint8(s, 3); /* version */ out_uint8(s, 0); /* reserved */ out_uint16_be(s, 11); /* length */ out_uint8(s, 6); /* hdrlen */ out_uint8(s, code); out_uint16(s, 0); /* dst_ref */ out_uint16(s, 0); /* src_ref */ out_uint8(s, 0); /* class */ s_mark_end(s); tcp_send(s); } static void iso_send_connection_request(char *username, uint32 neg_proto) { STREAM s; int length = 30 + strlen(username); if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol) length += 8; s = tcp_init(length); out_uint8(s, 3); /* version */ out_uint8(s, 0); /* reserved */ out_uint16_be(s, length); /* length */ out_uint8(s, length - 5); /* hdrlen */ out_uint8(s, ISO_PDU_CR); out_uint16(s, 0); /* dst_ref */ out_uint16(s, 0); /* src_ref */ out_uint8(s, 0); /* class */ out_uint8p(s, "Cookie: mstshash=", strlen("Cookie: mstshash=")); out_uint8p(s, username, strlen(username)); out_uint8(s, 0x0d); /* cookie termination string: CR+LF */ out_uint8(s, 0x0a); if (g_rdp_version >= RDP_V5 && g_negotiate_rdp_protocol) { /* optional rdp protocol negotiation request for RDPv5 */ out_uint8(s, RDP_NEG_REQ); out_uint8(s, 0); out_uint16(s, 8); out_uint32(s, neg_proto); } s_mark_end(s); tcp_send(s); } /* Receive a message on the ISO layer, return code */ static STREAM iso_recv_msg(uint8 * code, uint8 * rdpver) { STREAM s; uint16 length; uint8 version; s = tcp_recv(NULL, 4); if (s == NULL) return NULL; in_uint8(s, version); if (rdpver != NULL) *rdpver = version; if (version == 3) { in_uint8s(s, 1); /* pad */ in_uint16_be(s, length); } else { in_uint8(s, length); if (length & 0x80) { length &= ~0x80; next_be(s, length); } } if (length < 4) { error("Bad packet header\n"); return NULL; } s = tcp_recv(s, length - 4); if (s == NULL) return NULL; if (version != 3) return s; in_uint8s(s, 1); /* hdrlen */ in_uint8(s, *code); if (*code == ISO_PDU_DT) { in_uint8s(s, 1); /* eot */ return s; } in_uint8s(s, 5); /* dst_ref, src_ref, class */ return s; } /* Initialise ISO transport data packet */ STREAM iso_init(int length) { STREAM s; s = tcp_init(length + 7); s_push_layer(s, iso_hdr, 7); return s; } /* Send an ISO data PDU */ void iso_send(STREAM s) { uint16 length; s_pop_layer(s, iso_hdr); length = s->end - s->p; out_uint8(s, 3); /* version */ out_uint8(s, 0); /* reserved */ out_uint16_be(s, length); out_uint8(s, 2); /* hdrlen */ out_uint8(s, ISO_PDU_DT); /* code */ out_uint8(s, 0x80); /* eot */ tcp_send(s); } /* Receive ISO transport data packet */ STREAM iso_recv(uint8 * rdpver) { STREAM s; uint8 code = 0; s = iso_recv_msg(&code, rdpver); if (s == NULL) return NULL; if (rdpver != NULL) if (*rdpver != 3) return s; if (code != ISO_PDU_DT) { error("expected DT, got 0x%x\n", code); return NULL; } return s; } /* Establish a connection up to the ISO layer */ RD_BOOL iso_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol) { STREAM s; uint8 code; uint32 neg_proto; g_negotiate_rdp_protocol = True; neg_proto = PROTOCOL_SSL; #ifdef WITH_CREDSSP if (!g_use_password_as_pin) neg_proto |= PROTOCOL_HYBRID; else if (g_sc_csp_name || g_sc_reader_name || g_sc_card_name || g_sc_container_name) neg_proto |= PROTOCOL_HYBRID; else warning("Disables CredSSP due to missing smartcard information for SSO.\n"); #endif retry: *selected_protocol = PROTOCOL_RDP; code = 0; if (!tcp_connect(server)) return False; iso_send_connection_request(username, neg_proto); s = iso_recv_msg(&code, NULL); if (s == NULL) return False; if (code != ISO_PDU_CC) { error("expected CC, got 0x%x\n", code); tcp_disconnect(); return False; } if (g_rdp_version >= RDP_V5 && s_check_rem(s, 8)) { /* handle RDP_NEG_REQ response */ const char *reason = NULL; uint8 type = 0, flags = 0; uint16 length = 0; uint32 data = 0; in_uint8(s, type); in_uint8(s, flags); in_uint16(s, length); in_uint32(s, data); if (type == RDP_NEG_FAILURE) { RD_BOOL retry_without_neg = False; switch (data) { case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER: reason = "SSL with user authentication required by server"; break; case SSL_NOT_ALLOWED_BY_SERVER: reason = "SSL not allowed by server"; retry_without_neg = True; break; case SSL_CERT_NOT_ON_SERVER: reason = "no valid authentication certificate on server"; retry_without_neg = True; break; case INCONSISTENT_FLAGS: reason = "inconsistent negotiation flags"; break; case SSL_REQUIRED_BY_SERVER: reason = "SSL required by server"; break; case HYBRID_REQUIRED_BY_SERVER: reason = "CredSSP required by server"; break; default: reason = "unknown reason"; } tcp_disconnect(); if (retry_without_neg) { fprintf(stderr, "Failed to negotiate protocol, retrying with plain RDP.\n"); g_negotiate_rdp_protocol = False; goto retry; } fprintf(stderr, "Failed to connect, %s.\n", reason); return False; } if (type != RDP_NEG_RSP) { tcp_disconnect(); error("Expected RDP_NEG_RSP, got type = 0x%x\n", type); return False; } /* handle negotiation response */ if (data == PROTOCOL_SSL) { if (!tcp_tls_connect()) { /* failed to connect using cssp, let retry with plain TLS */ tcp_disconnect(); neg_proto = PROTOCOL_RDP; goto retry; } /* do not use encryption when using TLS */ g_encryption = False; fprintf(stderr, "Connection established using SSL.\n"); } #ifdef WITH_CREDSSP else if (data == PROTOCOL_HYBRID) { if (!cssp_connect(server, username, domain, password, s)) { /* failed to connect using cssp, let retry with plain TLS */ tcp_disconnect(); neg_proto = PROTOCOL_SSL; goto retry; } /* do not use encryption when using TLS */ fprintf(stderr, "Connection established using CredSSP.\n"); g_encryption = False; } #endif else if (data == PROTOCOL_RDP) { fprintf(stderr, "Connection established using plain RDP.\n"); } else if (data != PROTOCOL_RDP) { tcp_disconnect(); error("Unexpected protocol in negotiation response, got data = 0x%x.\n", data); return False; } *selected_protocol = data; } return True; } /* Disconnect from the ISO layer */ void iso_disconnect(void) { iso_send_msg(ISO_PDU_DR); tcp_disconnect(); } /* reset the state to support reconnecting */ void iso_reset_state(void) { g_encryption = g_encryption_initial; tcp_reset_state(); } rdesktop-1.8.3/licence.c0000664000770100510440000002522612336664005014057 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. RDP licensing negotiation Copyright (C) Matthew Chapman 1999-2008 Copyright (C) Thomas Uhle 2011 Copyright (C) Henrik Andersson 2014 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 3 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, see . */ #include "rdesktop.h" #include "ssl.h" extern char *g_username; extern char g_hostname[16]; extern RDP_VERSION g_rdp_version; static uint8 g_licence_key[16]; static uint8 g_licence_sign_key[16]; RD_BOOL g_licence_issued = False; RD_BOOL g_licence_error_result = False; /* Generate a session key and RC4 keys, given client and server randoms */ static void licence_generate_keys(uint8 * client_random, uint8 * server_random, uint8 * pre_master_secret) { uint8 master_secret[48]; uint8 key_block[48]; /* Generate master secret and then key material */ sec_hash_48(master_secret, pre_master_secret, client_random, server_random, 'A'); sec_hash_48(key_block, master_secret, server_random, client_random, 'A'); /* Store first 16 bytes of session key as MAC secret */ memcpy(g_licence_sign_key, key_block, 16); /* Generate RC4 key from next 16 bytes */ sec_hash_16(g_licence_key, &key_block[16], client_random, server_random); } static void licence_generate_hwid(uint8 * hwid) { buf_out_uint32(hwid, 2); strncpy((char *) (hwid + 4), g_hostname, LICENCE_HWID_SIZE - 4); } /* Send a lincece info packet to server */ static void licence_info(uint8 * client_random, uint8 * rsa_data, uint8 * licence_data, int licence_size, uint8 * hwid, uint8 * signature) { uint32 sec_flags = SEC_LICENCE_NEG; uint16 length = 24 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE; STREAM s; s = sec_init(sec_flags, length + 2); out_uint8(s, LICENCE_TAG_LICENCE_INFO); out_uint8(s, ((g_rdp_version >= RDP_V5) ? 3 : 2)); /* version */ out_uint16_le(s, length); out_uint32_le(s, 1); out_uint16(s, 0); out_uint16_le(s, 0x0201); out_uint8p(s, client_random, SEC_RANDOM_SIZE); out_uint16_le(s, 2); out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); out_uint8p(s, rsa_data, SEC_MODULUS_SIZE); out_uint8s(s, SEC_PADDING_SIZE); out_uint16_le(s, 1); out_uint16_le(s, licence_size); out_uint8p(s, licence_data, licence_size); out_uint16_le(s, 1); out_uint16_le(s, LICENCE_HWID_SIZE); out_uint8p(s, hwid, LICENCE_HWID_SIZE); out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE); s_mark_end(s); sec_send(s, sec_flags); } /* Send a new licence request packet */ static void licence_send_new_licence_request(uint8 * client_random, uint8 * rsa_data, char *user, char *host) { uint32 sec_flags = SEC_LICENCE_NEG; uint16 userlen = strlen(user) + 1; uint16 hostlen = strlen(host) + 1; uint16 length = 24 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + userlen + hostlen; STREAM s; s = sec_init(sec_flags, length + 2); out_uint8(s, LICENCE_TAG_NEW_LICENCE_REQUEST); out_uint8(s, ((g_rdp_version >= RDP_V5) ? 3 : 2)); /* version */ out_uint16_le(s, length); out_uint32_le(s, 1); // KEY_EXCHANGE_ALG_RSA out_uint16(s, 0); out_uint16_le(s, 0xff01); out_uint8p(s, client_random, SEC_RANDOM_SIZE); out_uint16_le(s, 2); out_uint16_le(s, (SEC_MODULUS_SIZE + SEC_PADDING_SIZE)); out_uint8p(s, rsa_data, SEC_MODULUS_SIZE); out_uint8s(s, SEC_PADDING_SIZE); /* Username LICENSE_BINARY_BLOB */ out_uint16_le(s, BB_CLIENT_USER_NAME_BLOB); out_uint16_le(s, userlen); out_uint8p(s, user, userlen); /* Machinename LICENSE_BINARY_BLOB */ out_uint16_le(s, BB_CLIENT_MACHINE_NAME_BLOB); out_uint16_le(s, hostlen); out_uint8p(s, host, hostlen); s_mark_end(s); sec_send(s, sec_flags); } /* Process a licence request packet */ static void licence_process_request(STREAM s) { uint8 null_data[SEC_MODULUS_SIZE]; uint8 *server_random; uint8 signature[LICENCE_SIGNATURE_SIZE]; uint8 hwid[LICENCE_HWID_SIZE]; uint8 *licence_data; int licence_size; RDSSL_RC4 crypt_key; /* Retrieve the server random from the incoming packet */ in_uint8p(s, server_random, SEC_RANDOM_SIZE); /* We currently use null client keys. This is a bit naughty but, hey, the security of licence negotiation isn't exactly paramount. */ memset(null_data, 0, sizeof(null_data)); licence_generate_keys(null_data, server_random, null_data); licence_size = load_licence(&licence_data); if (licence_size > 0) { /* Generate a signature for the HWID buffer */ licence_generate_hwid(hwid); sec_sign(signature, 16, g_licence_sign_key, 16, hwid, sizeof(hwid)); /* Now encrypt the HWID */ rdssl_rc4_set_key(&crypt_key, g_licence_key, 16); rdssl_rc4_crypt(&crypt_key, hwid, hwid, sizeof(hwid)); #if WITH_DEBUG DEBUG(("Sending licensing PDU (message type 0x%02x)\n", LICENCE_TAG_LICENCE_INFO)); #endif licence_info(null_data, null_data, licence_data, licence_size, hwid, signature); xfree(licence_data); return; } #if WITH_DEBUG DEBUG(("Sending licensing PDU (message type 0x%02x)\n", LICENCE_TAG_NEW_LICENCE_REQUEST)); #endif licence_send_new_licence_request(null_data, null_data, g_username, g_hostname); } /* Send a platform challange response packet */ static void licence_send_platform_challange_response(uint8 * token, uint8 * crypt_hwid, uint8 * signature) { uint32 sec_flags = SEC_LICENCE_NEG; uint16 length = 58; STREAM s; s = sec_init(sec_flags, length + 2); out_uint8(s, LICENCE_TAG_PLATFORM_CHALLANGE_RESPONSE); out_uint8(s, ((g_rdp_version >= RDP_V5) ? 3 : 2)); /* version */ out_uint16_le(s, length); out_uint16_le(s, 1); out_uint16_le(s, LICENCE_TOKEN_SIZE); out_uint8p(s, token, LICENCE_TOKEN_SIZE); out_uint16_le(s, 1); out_uint16_le(s, LICENCE_HWID_SIZE); out_uint8p(s, crypt_hwid, LICENCE_HWID_SIZE); out_uint8p(s, signature, LICENCE_SIGNATURE_SIZE); s_mark_end(s); sec_send(s, sec_flags); } /* Parse an platform challange request packet */ static RD_BOOL licence_parse_platform_challange(STREAM s, uint8 ** token, uint8 ** signature) { uint16 tokenlen; in_uint8s(s, 6); /* unknown: f8 3d 15 00 04 f6 */ in_uint16_le(s, tokenlen); if (tokenlen != LICENCE_TOKEN_SIZE) { error("token len %d\n", tokenlen); return False; } in_uint8p(s, *token, tokenlen); in_uint8p(s, *signature, LICENCE_SIGNATURE_SIZE); return s_check_end(s); } /* Process a platform challange packet */ static void licence_process_platform_challange(STREAM s) { uint8 *in_token = NULL, *in_sig; uint8 out_token[LICENCE_TOKEN_SIZE], decrypt_token[LICENCE_TOKEN_SIZE]; uint8 hwid[LICENCE_HWID_SIZE], crypt_hwid[LICENCE_HWID_SIZE]; uint8 sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE]; uint8 out_sig[LICENCE_SIGNATURE_SIZE]; RDSSL_RC4 crypt_key; /* Parse incoming packet and save the encrypted token */ licence_parse_platform_challange(s, &in_token, &in_sig); memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); /* Decrypt the token. It should read TEST in Unicode. */ rdssl_rc4_set_key(&crypt_key, g_licence_key, 16); rdssl_rc4_crypt(&crypt_key, in_token, decrypt_token, LICENCE_TOKEN_SIZE); /* Generate a signature for a buffer of token and HWID */ licence_generate_hwid(hwid); memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE); memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE); sec_sign(out_sig, 16, g_licence_sign_key, 16, sealed_buffer, sizeof(sealed_buffer)); /* Now encrypt the HWID */ rdssl_rc4_set_key(&crypt_key, g_licence_key, 16); rdssl_rc4_crypt(&crypt_key, hwid, crypt_hwid, LICENCE_HWID_SIZE); licence_send_platform_challange_response(out_token, crypt_hwid, out_sig); } /* Process a new licence packet */ static void licence_process_new_license(STREAM s) { RDSSL_RC4 crypt_key; uint32 length; int i; in_uint8s(s, 2); // Skip license binary blob type in_uint16_le(s, length); if (!s_check_rem(s, length)) return; rdssl_rc4_set_key(&crypt_key, g_licence_key, 16); rdssl_rc4_crypt(&crypt_key, s->p, s->p, length); /* Parse NEW_LICENSE_INFO block */ in_uint8s(s, 4); // skip dwVersion /* Skip strings, Scope, CompanyName and ProductId to get to the LicenseInfo which we store in license blob. */ length = 0; for (i = 0; i < 4; i++) { in_uint8s(s, length); in_uint32_le(s, length); if (!s_check_rem(s, length)) return; } g_licence_issued = True; save_licence(s->p, length); } /* process a licence error alert packet */ void licence_process_error_alert(STREAM s) { uint32 error_code; uint32 state_transition; uint32 error_info; in_uint32(s, error_code); in_uint32(s, state_transition); in_uint32(s, error_info); /* There is a special case in the error alert handling, when licensing is all good and the server is not sending a license to client, a "Server License Error PDU - Valid Client" packet is sent which means, every thing is ok. Therefor we should flag that everything is ok with license here. */ if (error_code == 0x07) { g_licence_issued = True; return; } /* handle error codes, for now, jsut report them */ switch (error_code) { case 0x6: // ERR_NO_LICENSE_SERVER warning("License error alert from server: No license server\n"); break; case 0x8: // ERR_INVALID_CLIENT warning("License error alert from server: Invalid client\n"); break; case 0x4: // ERR_INVALID_SCOPE case 0xb: // ERR_INVALID_PRODUCTID case 0xc: // ERR_INVALID_MESSAGE_LENGTH default: warning("License error alert from server: code %u, state transition %u\n", error_code, state_transition); break; } g_licence_error_result = True; } /* Process a licence packet */ void licence_process(STREAM s) { uint8 tag; in_uint8(s, tag); in_uint8s(s, 3); /* version, length */ #if WITH_DEBUG DEBUG(("Received licensing PDU (message type 0x%02x)\n", tag)); #endif switch (tag) { case LICENCE_TAG_REQUEST: licence_process_request(s); break; case LICENCE_TAG_PLATFORM_CHALLANGE: licence_process_platform_challange(s); break; case LICENCE_TAG_NEW_LICENCE: case LICENCE_TAG_UPGRADE_LICENCE: /* we can handle new and upgrades of licences the same way. */ licence_process_new_license(s); break; case LICENCE_TAG_ERROR_ALERT: licence_process_error_alert(s); break; default: unimpl("licence tag 0x%02x\n", tag); } } rdesktop-1.8.3/lspci.c0000664000770100510440000001061611323031512013546 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Support for the Matrox "lspci" channel Copyright (C) 2005 Matrox Graphics Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 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, see . */ #include "rdesktop.h" #include #include static VCHANNEL *lspci_channel; typedef struct _pci_device { uint16 klass; uint16 vendor; uint16 device; uint16 subvendor; uint16 subdevice; uint8 revision; uint8 progif; } pci_device; static pci_device current_device; static void lspci_send(const char *output); /* Handle one line of output from the lspci subprocess */ static RD_BOOL handle_child_line(const char *line, void *data) { const char *val; char buf[1024]; if (str_startswith(line, "Class:")) { val = line + sizeof("Class:"); /* Skip whitespace and second Class: occurance */ val += strspn(val, " \t") + sizeof("Class"); current_device.klass = strtol(val, NULL, 16); } else if (str_startswith(line, "Vendor:")) { val = line + sizeof("Vendor:"); current_device.vendor = strtol(val, NULL, 16); } else if (str_startswith(line, "Device:")) { val = line + sizeof("Device:"); /* Sigh, there are *two* lines tagged as Device:. We are not interested in the domain/bus/slot/func */ if (!strchr(val, ':')) current_device.device = strtol(val, NULL, 16); } else if (str_startswith(line, "SVendor:")) { val = line + sizeof("SVendor:"); current_device.subvendor = strtol(val, NULL, 16); } else if (str_startswith(line, "SDevice:")) { val = line + sizeof("SDevice:"); current_device.subdevice = strtol(val, NULL, 16); } else if (str_startswith(line, "Rev:")) { val = line + sizeof("Rev:"); current_device.revision = strtol(val, NULL, 16); } else if (str_startswith(line, "ProgIf:")) { val = line + sizeof("ProgIf:"); current_device.progif = strtol(val, NULL, 16); } else if (strspn(line, " \t") == strlen(line)) { /* Blank line. Send collected information over channel */ snprintf(buf, sizeof(buf), "%04x,%04x,%04x,%04x,%04x,%02x,%02x\n", current_device.klass, current_device.vendor, current_device.device, current_device.subvendor, current_device.subdevice, current_device.revision, current_device.progif); lspci_send(buf); memset(¤t_device, 0, sizeof(current_device)); } else { warning("lspci: Unrecoqnized line '%s'\n", line); } return True; } /* Process one line of input from virtual channel */ static RD_BOOL lspci_process_line(const char *line, void *data) { char *lspci_command[5] = { "lspci", "-m", "-n", "-v", NULL }; if (!strcmp(line, "LSPCI")) { memset(¤t_device, 0, sizeof(current_device)); subprocess(lspci_command, handle_child_line, NULL); /* Send single dot to indicate end of enumeration */ lspci_send(".\n"); } else { error("lspci protocol error: Invalid line '%s'\n", line); } return True; } /* Process new data from the virtual channel */ static void lspci_process(STREAM s) { unsigned int pkglen; static char *rest = NULL; char *buf; pkglen = s->end - s->p; /* str_handle_lines requires null terminated strings */ buf = xmalloc(pkglen + 1); STRNCPY(buf, (char *) s->p, pkglen + 1); #if 0 printf("lspci recv:\n"); hexdump(s->p, pkglen); #endif str_handle_lines(buf, &rest, lspci_process_line, NULL); xfree(buf); } /* Initialize this module: Register the lspci channel */ RD_BOOL lspci_init(void) { lspci_channel = channel_register("lspci", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, lspci_process); return (lspci_channel != NULL); } /* Send data to channel */ static void lspci_send(const char *output) { STREAM s; size_t len; len = strlen(output); s = channel_init(lspci_channel, len); out_uint8p(s, output, len) s_mark_end(s); #if 0 printf("lspci send:\n"); hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); #endif channel_send(s, lspci_channel); } rdesktop-1.8.3/mcs.c0000664000770100510440000001656512051150035013230 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - Multipoint Communications Service Copyright (C) Matthew Chapman 1999-2008 Copyright 2005-2011 Peter Astrand for Cendio AB 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 3 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, see . */ #include "rdesktop.h" uint16 g_mcs_userid; extern VCHANNEL g_channels[]; extern unsigned int g_num_channels; /* Output a DOMAIN_PARAMS structure (ASN.1 BER) */ static void mcs_out_domain_params(STREAM s, int max_channels, int max_users, int max_tokens, int max_pdusize) { ber_out_header(s, MCS_TAG_DOMAIN_PARAMS, 32); ber_out_integer(s, max_channels); ber_out_integer(s, max_users); ber_out_integer(s, max_tokens); ber_out_integer(s, 1); /* num_priorities */ ber_out_integer(s, 0); /* min_throughput */ ber_out_integer(s, 1); /* max_height */ ber_out_integer(s, max_pdusize); ber_out_integer(s, 2); /* ver_protocol */ } /* Parse a DOMAIN_PARAMS structure (ASN.1 BER) */ static RD_BOOL mcs_parse_domain_params(STREAM s) { int length; ber_parse_header(s, MCS_TAG_DOMAIN_PARAMS, &length); in_uint8s(s, length); return s_check(s); } /* Send an MCS_CONNECT_INITIAL message (ASN.1 BER) */ static void mcs_send_connect_initial(STREAM mcs_data) { int datalen = mcs_data->end - mcs_data->data; int length = 9 + 3 * 34 + 4 + datalen; STREAM s; s = iso_init(length + 5); ber_out_header(s, MCS_CONNECT_INITIAL, length); ber_out_header(s, BER_TAG_OCTET_STRING, 1); /* calling domain */ out_uint8(s, 1); ber_out_header(s, BER_TAG_OCTET_STRING, 1); /* called domain */ out_uint8(s, 1); ber_out_header(s, BER_TAG_BOOLEAN, 1); out_uint8(s, 0xff); /* upward flag */ mcs_out_domain_params(s, 34, 2, 0, 0xffff); /* target params */ mcs_out_domain_params(s, 1, 1, 1, 0x420); /* min params */ mcs_out_domain_params(s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */ ber_out_header(s, BER_TAG_OCTET_STRING, datalen); out_uint8p(s, mcs_data->data, datalen); s_mark_end(s); iso_send(s); } /* Expect a MCS_CONNECT_RESPONSE message (ASN.1 BER) */ static RD_BOOL mcs_recv_connect_response(STREAM mcs_data) { uint8 result; int length; STREAM s; s = iso_recv(NULL); if (s == NULL) return False; ber_parse_header(s, MCS_CONNECT_RESPONSE, &length); ber_parse_header(s, BER_TAG_RESULT, &length); in_uint8(s, result); if (result != 0) { error("MCS connect: %d\n", result); return False; } ber_parse_header(s, BER_TAG_INTEGER, &length); in_uint8s(s, length); /* connect id */ mcs_parse_domain_params(s); ber_parse_header(s, BER_TAG_OCTET_STRING, &length); sec_process_mcs_data(s); /* if (length > mcs_data->size) { error("MCS data length %d, expected %d\n", length, mcs_data->size); length = mcs_data->size; } in_uint8a(s, mcs_data->data, length); mcs_data->p = mcs_data->data; mcs_data->end = mcs_data->data + length; */ return s_check_end(s); } /* Send an EDrq message (ASN.1 PER) */ static void mcs_send_edrq(void) { STREAM s; s = iso_init(5); out_uint8(s, (MCS_EDRQ << 2)); out_uint16_be(s, 1); /* height */ out_uint16_be(s, 1); /* interval */ s_mark_end(s); iso_send(s); } /* Send an AUrq message (ASN.1 PER) */ static void mcs_send_aurq(void) { STREAM s; s = iso_init(1); out_uint8(s, (MCS_AURQ << 2)); s_mark_end(s); iso_send(s); } /* Expect a AUcf message (ASN.1 PER) */ static RD_BOOL mcs_recv_aucf(uint16 * mcs_userid) { uint8 opcode, result; STREAM s; s = iso_recv(NULL); if (s == NULL) return False; in_uint8(s, opcode); if ((opcode >> 2) != MCS_AUCF) { error("expected AUcf, got %d\n", opcode); return False; } in_uint8(s, result); if (result != 0) { error("AUrq: %d\n", result); return False; } if (opcode & 2) in_uint16_be(s, *mcs_userid); return s_check_end(s); } /* Send a CJrq message (ASN.1 PER) */ static void mcs_send_cjrq(uint16 chanid) { STREAM s; DEBUG_RDP5(("Sending CJRQ for channel #%d\n", chanid)); s = iso_init(5); out_uint8(s, (MCS_CJRQ << 2)); out_uint16_be(s, g_mcs_userid); out_uint16_be(s, chanid); s_mark_end(s); iso_send(s); } /* Expect a CJcf message (ASN.1 PER) */ static RD_BOOL mcs_recv_cjcf(void) { uint8 opcode, result; STREAM s; s = iso_recv(NULL); if (s == NULL) return False; in_uint8(s, opcode); if ((opcode >> 2) != MCS_CJCF) { error("expected CJcf, got %d\n", opcode); return False; } in_uint8(s, result); if (result != 0) { error("CJrq: %d\n", result); return False; } in_uint8s(s, 4); /* mcs_userid, req_chanid */ if (opcode & 2) in_uint8s(s, 2); /* join_chanid */ return s_check_end(s); } /* Initialise an MCS transport data packet */ STREAM mcs_init(int length) { STREAM s; s = iso_init(length + 8); s_push_layer(s, mcs_hdr, 8); return s; } /* Send an MCS transport data packet to a specific channel */ void mcs_send_to_channel(STREAM s, uint16 channel) { uint16 length; s_pop_layer(s, mcs_hdr); length = s->end - s->p - 8; length |= 0x8000; out_uint8(s, (MCS_SDRQ << 2)); out_uint16_be(s, g_mcs_userid); out_uint16_be(s, channel); out_uint8(s, 0x70); /* flags */ out_uint16_be(s, length); iso_send(s); } /* Send an MCS transport data packet to the global channel */ void mcs_send(STREAM s) { mcs_send_to_channel(s, MCS_GLOBAL_CHANNEL); } /* Receive an MCS transport data packet */ STREAM mcs_recv(uint16 * channel, uint8 * rdpver) { uint8 opcode, appid, length; STREAM s; s = iso_recv(rdpver); if (s == NULL) return NULL; if (rdpver != NULL) if (*rdpver != 3) return s; in_uint8(s, opcode); appid = opcode >> 2; if (appid != MCS_SDIN) { if (appid != MCS_DPUM) { error("expected data, got %d\n", opcode); } return NULL; } in_uint8s(s, 2); /* userid */ in_uint16_be(s, *channel); in_uint8s(s, 1); /* flags */ in_uint8(s, length); if (length & 0x80) in_uint8s(s, 1); /* second byte of length */ return s; } RD_BOOL mcs_connect_start(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol) { return iso_connect(server, username, domain, password, reconnect, selected_protocol); } RD_BOOL mcs_connect_finalize(STREAM mcs_data) { unsigned int i; mcs_send_connect_initial(mcs_data); if (!mcs_recv_connect_response(mcs_data)) goto error; mcs_send_edrq(); mcs_send_aurq(); if (!mcs_recv_aucf(&g_mcs_userid)) goto error; mcs_send_cjrq(g_mcs_userid + MCS_USERCHANNEL_BASE); if (!mcs_recv_cjcf()) goto error; mcs_send_cjrq(MCS_GLOBAL_CHANNEL); if (!mcs_recv_cjcf()) goto error; for (i = 0; i < g_num_channels; i++) { mcs_send_cjrq(g_channels[i].mcs_id); if (!mcs_recv_cjcf()) goto error; } return True; error: iso_disconnect(); return False; } /* Disconnect from the MCS layer */ void mcs_disconnect(void) { iso_disconnect(); } /* reset the state of the mcs layer */ void mcs_reset_state(void) { g_mcs_userid = 0; iso_reset_state(); } rdesktop-1.8.3/mppc.c0000664000770100510440000002072511551302500013376 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP decompression Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ #include #include #include "rdesktop.h" /* mppc decompression */ /* http://www.faqs.org/rfcs/rfc2118.html */ /* Contacts: */ /* hifn contact mentioned in the faq is */ /* Robert Friend rfriend at hifn dot com */ /* if you have questions regarding MPPC */ /* our contact is */ /* Guus Dhaeze GDhaeze at hifn dot com */ /* Licensing: */ /* decompression is alright as long as we */ /* don't compress data */ /* Algorithm: */ /* as the rfc states the algorithm seems to */ /* be LZ77 with a sliding buffer */ /* that is empty at init. */ /* the algorithm is called LZS and is */ /* patented for another couple of years. */ /* more information is available in */ /* http://www.ietf.org/ietf/IPR/hifn-ipr-draft-friend-tls-lzs-compression.txt */ RDPCOMP g_mppc_dict; int mppc_expand(uint8 * data, uint32 clen, uint8 ctype, uint32 * roff, uint32 * rlen) { int k, walker_len = 0, walker; uint32 i = 0; int next_offset, match_off; int match_len; int old_offset, match_bits; RD_BOOL big = ctype & RDP_MPPC_BIG ? True : False; uint8 *dict = g_mppc_dict.hist; if ((ctype & RDP_MPPC_COMPRESSED) == 0) { *roff = 0; *rlen = clen; return 0; } if ((ctype & RDP_MPPC_RESET) != 0) { g_mppc_dict.roff = 0; } if ((ctype & RDP_MPPC_FLUSH) != 0) { memset(dict, 0, RDP_MPPC_DICT_SIZE); g_mppc_dict.roff = 0; } *roff = 0; *rlen = 0; walker = g_mppc_dict.roff; next_offset = walker; old_offset = next_offset; *roff = old_offset; if (clen == 0) return 0; clen += i; do { if (walker_len == 0) { if (i >= clen) break; walker = data[i++] << 24; walker_len = 8; } if (walker >= 0) { if (walker_len < 8) { if (i >= clen) { if (walker != 0) return -1; break; } walker |= (data[i++] & 0xff) << (24 - walker_len); walker_len += 8; } if (next_offset >= RDP_MPPC_DICT_SIZE) return -1; dict[next_offset++] = (((uint32) walker) >> ((uint32) 24)); walker <<= 8; walker_len -= 8; continue; } walker <<= 1; /* fetch next 8-bits */ if (--walker_len == 0) { if (i >= clen) return -1; walker = data[i++] << 24; walker_len = 8; } /* literal decoding */ if (walker >= 0) { if (walker_len < 8) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); walker_len += 8; } if (next_offset >= RDP_MPPC_DICT_SIZE) return -1; dict[next_offset++] = (uint8) (walker >> 24 | 0x80); walker <<= 8; walker_len -= 8; continue; } /* decode offset */ /* length pair */ walker <<= 1; if (--walker_len < (big ? 3 : 2)) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); walker_len += 8; } if (big) { /* offset decoding where offset len is: -63: 11111 followed by the lower 6 bits of the value 64-319: 11110 followed by the lower 8 bits of the value ( value - 64 ) 320-2367: 1110 followed by lower 11 bits of the value ( value - 320 ) 2368-65535: 110 followed by lower 16 bits of the value ( value - 2368 ) */ switch (((uint32) walker) >> ((uint32) 29)) { case 7: /* - 63 */ for (; walker_len < 9; walker_len += 8) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); } walker <<= 3; match_off = ((uint32) walker) >> ((uint32) 26); walker <<= 6; walker_len -= 9; break; case 6: /* 64 - 319 */ for (; walker_len < 11; walker_len += 8) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); } walker <<= 3; match_off = (((uint32) walker) >> ((uint32) 24)) + 64; walker <<= 8; walker_len -= 11; break; case 5: case 4: /* 320 - 2367 */ for (; walker_len < 13; walker_len += 8) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); } walker <<= 2; match_off = (((uint32) walker) >> ((uint32) 21)) + 320; walker <<= 11; walker_len -= 13; break; default: /* 2368 - 65535 */ for (; walker_len < 17; walker_len += 8) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); } walker <<= 1; match_off = (((uint32) walker) >> ((uint32) 16)) + 2368; walker <<= 16; walker_len -= 17; break; } } else { /* offset decoding where offset len is: -63: 1111 followed by the lower 6 bits of the value 64-319: 1110 followed by the lower 8 bits of the value ( value - 64 ) 320-8191: 110 followed by the lower 13 bits of the value ( value - 320 ) */ switch (((uint32) walker) >> ((uint32) 30)) { case 3: /* - 63 */ if (walker_len < 8) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); walker_len += 8; } walker <<= 2; match_off = ((uint32) walker) >> ((uint32) 26); walker <<= 6; walker_len -= 8; break; case 2: /* 64 - 319 */ for (; walker_len < 10; walker_len += 8) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); } walker <<= 2; match_off = (((uint32) walker) >> ((uint32) 24)) + 64; walker <<= 8; walker_len -= 10; break; default: /* 320 - 8191 */ for (; walker_len < 14; walker_len += 8) { if (i >= clen) return -1; walker |= (data[i++] & 0xff) << (24 - walker_len); } match_off = (walker >> 18) + 320; walker <<= 14; walker_len -= 14; break; } } if (walker_len == 0) { if (i >= clen) return -1; walker = data[i++] << 24; walker_len = 8; } /* decode length of match */ match_len = 0; if (walker >= 0) { /* special case - length of 3 is in bit 0 */ match_len = 3; walker <<= 1; walker_len--; } else { /* this is how it works len of: 4-7: 10 followed by 2 bits of the value 8-15: 110 followed by 3 bits of the value 16-31: 1110 followed by 4 bits of the value 32-63: .... and so forth 64-127: 128-255: 256-511: 512-1023: 1024-2047: 2048-4095: 4096-8191: i.e. 4097 is encoded as: 111111111110 000000000001 meaning 4096 + 1... */ match_bits = big ? 14 : 11; /* 11 or 14 bits of value at most */ do { walker <<= 1; if (--walker_len == 0) { if (i >= clen) return -1; walker = data[i++] << 24; walker_len = 8; } if (walker >= 0) break; if (--match_bits == 0) { return -1; } } while (1); match_len = (big ? 16 : 13) - match_bits; walker <<= 1; if (--walker_len < match_len) { for (; walker_len < match_len; walker_len += 8) { if (i >= clen) { return -1; } walker |= (data[i++] & 0xff) << (24 - walker_len); } } match_bits = match_len; match_len = ((walker >> (32 - match_bits)) & (~(-1 << match_bits))) | (1 << match_bits); walker <<= match_bits; walker_len -= match_bits; } if (next_offset + match_len >= RDP_MPPC_DICT_SIZE) { return -1; } /* memory areas can overlap - meaning we can't use memXXX functions */ k = (next_offset - match_off) & (big ? 65535 : 8191); do { dict[next_offset++] = dict[k++]; } while (--match_len != 0); } while (1); /* store history offset */ g_mppc_dict.roff = next_offset; *roff = old_offset; *rlen = next_offset - old_offset; return 0; } rdesktop-1.8.3/orders.c0000664000770100510440000007644311766542444013772 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. RDP order processing Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ #include "rdesktop.h" #include "orders.h" extern uint8 *g_next_packet; static RDP_ORDER_STATE g_order_state; extern RDP_VERSION g_rdp_version; /* Read field indicating which parameters are present */ static void rdp_in_present(STREAM s, uint32 * present, uint8 flags, int size) { uint8 bits; int i; if (flags & RDP_ORDER_SMALL) { size--; } if (flags & RDP_ORDER_TINY) { if (size < 2) size = 0; else size -= 2; } *present = 0; for (i = 0; i < size; i++) { in_uint8(s, bits); *present |= bits << (i * 8); } } /* Read a co-ordinate (16-bit, or 8-bit delta) */ static void rdp_in_coord(STREAM s, sint16 * coord, RD_BOOL delta) { sint8 change; if (delta) { in_uint8(s, change); *coord += change; } else { in_uint16_le(s, *coord); } } /* Parse a delta co-ordinate in polyline/polygon order form */ static int parse_delta(uint8 * buffer, int *offset) { int value = buffer[(*offset)++]; int two_byte = value & 0x80; if (value & 0x40) /* sign bit */ value |= ~0x3f; else value &= 0x3f; if (two_byte) value = (value << 8) | buffer[(*offset)++]; return value; } /* Read a colour entry */ static void rdp_in_colour(STREAM s, uint32 * colour) { uint32 i; in_uint8(s, i); *colour = i; in_uint8(s, i); *colour |= i << 8; in_uint8(s, i); *colour |= i << 16; } /* Parse bounds information */ static RD_BOOL rdp_parse_bounds(STREAM s, BOUNDS * bounds) { uint8 present; in_uint8(s, present); if (present & 1) rdp_in_coord(s, &bounds->left, False); else if (present & 16) rdp_in_coord(s, &bounds->left, True); if (present & 2) rdp_in_coord(s, &bounds->top, False); else if (present & 32) rdp_in_coord(s, &bounds->top, True); if (present & 4) rdp_in_coord(s, &bounds->right, False); else if (present & 64) rdp_in_coord(s, &bounds->right, True); if (present & 8) rdp_in_coord(s, &bounds->bottom, False); else if (present & 128) rdp_in_coord(s, &bounds->bottom, True); return s_check(s); } /* Parse a pen */ static RD_BOOL rdp_parse_pen(STREAM s, PEN * pen, uint32 present) { if (present & 1) in_uint8(s, pen->style); if (present & 2) in_uint8(s, pen->width); if (present & 4) rdp_in_colour(s, &pen->colour); return s_check(s); } static void setup_brush(BRUSH * out_brush, BRUSH * in_brush) { BRUSHDATA *brush_data; uint8 cache_idx; uint8 colour_code; memcpy(out_brush, in_brush, sizeof(BRUSH)); if (out_brush->style & 0x80) { colour_code = out_brush->style & 0x0f; cache_idx = out_brush->pattern[0]; brush_data = cache_get_brush_data(colour_code, cache_idx); if ((brush_data == NULL) || (brush_data->data == NULL)) { error("error getting brush data, style %x\n", out_brush->style); out_brush->bd = NULL; memset(out_brush->pattern, 0, 8); } else { out_brush->bd = brush_data; } out_brush->style = 3; } } /* Parse a brush */ static RD_BOOL rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present) { if (present & 1) in_uint8(s, brush->xorigin); if (present & 2) in_uint8(s, brush->yorigin); if (present & 4) in_uint8(s, brush->style); if (present & 8) in_uint8(s, brush->pattern[0]); if (present & 16) in_uint8a(s, &brush->pattern[1], 7); return s_check(s); } /* Process a destination blt order */ static void process_destblt(STREAM s, DESTBLT_ORDER * os, uint32 present, RD_BOOL delta) { if (present & 0x01) rdp_in_coord(s, &os->x, delta); if (present & 0x02) rdp_in_coord(s, &os->y, delta); if (present & 0x04) rdp_in_coord(s, &os->cx, delta); if (present & 0x08) rdp_in_coord(s, &os->cy, delta); if (present & 0x10) in_uint8(s, os->opcode); DEBUG(("DESTBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d)\n", os->opcode, os->x, os->y, os->cx, os->cy)); ui_destblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy); } /* Process a pattern blt order */ static void process_patblt(STREAM s, PATBLT_ORDER * os, uint32 present, RD_BOOL delta) { BRUSH brush; if (present & 0x0001) rdp_in_coord(s, &os->x, delta); if (present & 0x0002) rdp_in_coord(s, &os->y, delta); if (present & 0x0004) rdp_in_coord(s, &os->cx, delta); if (present & 0x0008) rdp_in_coord(s, &os->cy, delta); if (present & 0x0010) in_uint8(s, os->opcode); if (present & 0x0020) rdp_in_colour(s, &os->bgcolour); if (present & 0x0040) rdp_in_colour(s, &os->fgcolour); rdp_parse_brush(s, &os->brush, present >> 7); DEBUG(("PATBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,bs=%d,bg=0x%x,fg=0x%x)\n", os->opcode, os->x, os->y, os->cx, os->cy, os->brush.style, os->bgcolour, os->fgcolour)); setup_brush(&brush, &os->brush); ui_patblt(ROP2_P(os->opcode), os->x, os->y, os->cx, os->cy, &brush, os->bgcolour, os->fgcolour); } /* Process a screen blt order */ static void process_screenblt(STREAM s, SCREENBLT_ORDER * os, uint32 present, RD_BOOL delta) { if (present & 0x0001) rdp_in_coord(s, &os->x, delta); if (present & 0x0002) rdp_in_coord(s, &os->y, delta); if (present & 0x0004) rdp_in_coord(s, &os->cx, delta); if (present & 0x0008) rdp_in_coord(s, &os->cy, delta); if (present & 0x0010) in_uint8(s, os->opcode); if (present & 0x0020) rdp_in_coord(s, &os->srcx, delta); if (present & 0x0040) rdp_in_coord(s, &os->srcy, delta); DEBUG(("SCREENBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,srcx=%d,srcy=%d)\n", os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy)); ui_screenblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, os->srcx, os->srcy); } /* Process a line order */ static void process_line(STREAM s, LINE_ORDER * os, uint32 present, RD_BOOL delta) { if (present & 0x0001) in_uint16_le(s, os->mixmode); if (present & 0x0002) rdp_in_coord(s, &os->startx, delta); if (present & 0x0004) rdp_in_coord(s, &os->starty, delta); if (present & 0x0008) rdp_in_coord(s, &os->endx, delta); if (present & 0x0010) rdp_in_coord(s, &os->endy, delta); if (present & 0x0020) rdp_in_colour(s, &os->bgcolour); if (present & 0x0040) in_uint8(s, os->opcode); rdp_parse_pen(s, &os->pen, present >> 7); DEBUG(("LINE(op=0x%x,sx=%d,sy=%d,dx=%d,dy=%d,fg=0x%x)\n", os->opcode, os->startx, os->starty, os->endx, os->endy, os->pen.colour)); if (os->opcode < 0x01 || os->opcode > 0x10) { error("bad ROP2 0x%x\n", os->opcode); return; } ui_line(os->opcode - 1, os->startx, os->starty, os->endx, os->endy, &os->pen); } /* Process an opaque rectangle order */ static void process_rect(STREAM s, RECT_ORDER * os, uint32 present, RD_BOOL delta) { uint32 i; if (present & 0x01) rdp_in_coord(s, &os->x, delta); if (present & 0x02) rdp_in_coord(s, &os->y, delta); if (present & 0x04) rdp_in_coord(s, &os->cx, delta); if (present & 0x08) rdp_in_coord(s, &os->cy, delta); if (present & 0x10) { in_uint8(s, i); os->colour = (os->colour & 0xffffff00) | i; } if (present & 0x20) { in_uint8(s, i); os->colour = (os->colour & 0xffff00ff) | (i << 8); } if (present & 0x40) { in_uint8(s, i); os->colour = (os->colour & 0xff00ffff) | (i << 16); } DEBUG(("RECT(x=%d,y=%d,cx=%d,cy=%d,fg=0x%x)\n", os->x, os->y, os->cx, os->cy, os->colour)); ui_rect(os->x, os->y, os->cx, os->cy, os->colour); } /* Process a desktop save order */ static void process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, RD_BOOL delta) { int width, height; if (present & 0x01) in_uint32_le(s, os->offset); if (present & 0x02) rdp_in_coord(s, &os->left, delta); if (present & 0x04) rdp_in_coord(s, &os->top, delta); if (present & 0x08) rdp_in_coord(s, &os->right, delta); if (present & 0x10) rdp_in_coord(s, &os->bottom, delta); if (present & 0x20) in_uint8(s, os->action); DEBUG(("DESKSAVE(l=%d,t=%d,r=%d,b=%d,off=%d,op=%d)\n", os->left, os->top, os->right, os->bottom, os->offset, os->action)); width = os->right - os->left + 1; height = os->bottom - os->top + 1; if (os->action == 0) ui_desktop_save(os->offset, os->left, os->top, width, height); else ui_desktop_restore(os->offset, os->left, os->top, width, height); } /* Process a memory blt order */ static void process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, RD_BOOL delta) { RD_HBITMAP bitmap; if (present & 0x0001) { in_uint8(s, os->cache_id); in_uint8(s, os->colour_table); } if (present & 0x0002) rdp_in_coord(s, &os->x, delta); if (present & 0x0004) rdp_in_coord(s, &os->y, delta); if (present & 0x0008) rdp_in_coord(s, &os->cx, delta); if (present & 0x0010) rdp_in_coord(s, &os->cy, delta); if (present & 0x0020) in_uint8(s, os->opcode); if (present & 0x0040) rdp_in_coord(s, &os->srcx, delta); if (present & 0x0080) rdp_in_coord(s, &os->srcy, delta); if (present & 0x0100) in_uint16_le(s, os->cache_idx); DEBUG(("MEMBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d)\n", os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx)); bitmap = cache_get_bitmap(os->cache_id, os->cache_idx); if (bitmap == NULL) return; ui_memblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, bitmap, os->srcx, os->srcy); } /* Process a 3-way blt order */ static void process_triblt(STREAM s, TRIBLT_ORDER * os, uint32 present, RD_BOOL delta) { RD_HBITMAP bitmap; BRUSH brush; if (present & 0x000001) { in_uint8(s, os->cache_id); in_uint8(s, os->colour_table); } if (present & 0x000002) rdp_in_coord(s, &os->x, delta); if (present & 0x000004) rdp_in_coord(s, &os->y, delta); if (present & 0x000008) rdp_in_coord(s, &os->cx, delta); if (present & 0x000010) rdp_in_coord(s, &os->cy, delta); if (present & 0x000020) in_uint8(s, os->opcode); if (present & 0x000040) rdp_in_coord(s, &os->srcx, delta); if (present & 0x000080) rdp_in_coord(s, &os->srcy, delta); if (present & 0x000100) rdp_in_colour(s, &os->bgcolour); if (present & 0x000200) rdp_in_colour(s, &os->fgcolour); rdp_parse_brush(s, &os->brush, present >> 10); if (present & 0x008000) in_uint16_le(s, os->cache_idx); if (present & 0x010000) in_uint16_le(s, os->unknown); DEBUG(("TRIBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d,bs=%d,bg=0x%x,fg=0x%x)\n", os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx, os->brush.style, os->bgcolour, os->fgcolour)); bitmap = cache_get_bitmap(os->cache_id, os->cache_idx); if (bitmap == NULL) return; setup_brush(&brush, &os->brush); ui_triblt(os->opcode, os->x, os->y, os->cx, os->cy, bitmap, os->srcx, os->srcy, &brush, os->bgcolour, os->fgcolour); } /* Process a polygon order */ static void process_polygon(STREAM s, POLYGON_ORDER * os, uint32 present, RD_BOOL delta) { int index, data, next; uint8 flags = 0; RD_POINT *points; if (present & 0x01) rdp_in_coord(s, &os->x, delta); if (present & 0x02) rdp_in_coord(s, &os->y, delta); if (present & 0x04) in_uint8(s, os->opcode); if (present & 0x08) in_uint8(s, os->fillmode); if (present & 0x10) rdp_in_colour(s, &os->fgcolour); if (present & 0x20) in_uint8(s, os->npoints); if (present & 0x40) { in_uint8(s, os->datasize); in_uint8a(s, os->data, os->datasize); } DEBUG(("POLYGON(x=%d,y=%d,op=0x%x,fm=%d,fg=0x%x,n=%d,sz=%d)\n", os->x, os->y, os->opcode, os->fillmode, os->fgcolour, os->npoints, os->datasize)); DEBUG(("Data: ")); for (index = 0; index < os->datasize; index++) DEBUG(("%02x ", os->data[index])); DEBUG(("\n")); if (os->opcode < 0x01 || os->opcode > 0x10) { error("bad ROP2 0x%x\n", os->opcode); return; } points = (RD_POINT *) xmalloc((os->npoints + 1) * sizeof(RD_POINT)); memset(points, 0, (os->npoints + 1) * sizeof(RD_POINT)); points[0].x = os->x; points[0].y = os->y; index = 0; data = ((os->npoints - 1) / 4) + 1; for (next = 1; (next <= os->npoints) && (next < 256) && (data < os->datasize); next++) { if ((next - 1) % 4 == 0) flags = os->data[index++]; if (~flags & 0x80) points[next].x = parse_delta(os->data, &data); if (~flags & 0x40) points[next].y = parse_delta(os->data, &data); flags <<= 2; } if (next - 1 == os->npoints) ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1, NULL, 0, os->fgcolour); else error("polygon parse error\n"); xfree(points); } /* Process a polygon2 order */ static void process_polygon2(STREAM s, POLYGON2_ORDER * os, uint32 present, RD_BOOL delta) { int index, data, next; uint8 flags = 0; RD_POINT *points; BRUSH brush; if (present & 0x0001) rdp_in_coord(s, &os->x, delta); if (present & 0x0002) rdp_in_coord(s, &os->y, delta); if (present & 0x0004) in_uint8(s, os->opcode); if (present & 0x0008) in_uint8(s, os->fillmode); if (present & 0x0010) rdp_in_colour(s, &os->bgcolour); if (present & 0x0020) rdp_in_colour(s, &os->fgcolour); rdp_parse_brush(s, &os->brush, present >> 6); if (present & 0x0800) in_uint8(s, os->npoints); if (present & 0x1000) { in_uint8(s, os->datasize); in_uint8a(s, os->data, os->datasize); } DEBUG(("POLYGON2(x=%d,y=%d,op=0x%x,fm=%d,bs=%d,bg=0x%x,fg=0x%x,n=%d,sz=%d)\n", os->x, os->y, os->opcode, os->fillmode, os->brush.style, os->bgcolour, os->fgcolour, os->npoints, os->datasize)); DEBUG(("Data: ")); for (index = 0; index < os->datasize; index++) DEBUG(("%02x ", os->data[index])); DEBUG(("\n")); if (os->opcode < 0x01 || os->opcode > 0x10) { error("bad ROP2 0x%x\n", os->opcode); return; } setup_brush(&brush, &os->brush); points = (RD_POINT *) xmalloc((os->npoints + 1) * sizeof(RD_POINT)); memset(points, 0, (os->npoints + 1) * sizeof(RD_POINT)); points[0].x = os->x; points[0].y = os->y; index = 0; data = ((os->npoints - 1) / 4) + 1; for (next = 1; (next <= os->npoints) && (next < 256) && (data < os->datasize); next++) { if ((next - 1) % 4 == 0) flags = os->data[index++]; if (~flags & 0x80) points[next].x = parse_delta(os->data, &data); if (~flags & 0x40) points[next].y = parse_delta(os->data, &data); flags <<= 2; } if (next - 1 == os->npoints) ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1, &brush, os->bgcolour, os->fgcolour); else error("polygon2 parse error\n"); xfree(points); } /* Process a polyline order */ static void process_polyline(STREAM s, POLYLINE_ORDER * os, uint32 present, RD_BOOL delta) { int index, next, data; uint8 flags = 0; PEN pen; RD_POINT *points; if (present & 0x01) rdp_in_coord(s, &os->x, delta); if (present & 0x02) rdp_in_coord(s, &os->y, delta); if (present & 0x04) in_uint8(s, os->opcode); if (present & 0x10) rdp_in_colour(s, &os->fgcolour); if (present & 0x20) in_uint8(s, os->lines); if (present & 0x40) { in_uint8(s, os->datasize); in_uint8a(s, os->data, os->datasize); } DEBUG(("POLYLINE(x=%d,y=%d,op=0x%x,fg=0x%x,n=%d,sz=%d)\n", os->x, os->y, os->opcode, os->fgcolour, os->lines, os->datasize)); DEBUG(("Data: ")); for (index = 0; index < os->datasize; index++) DEBUG(("%02x ", os->data[index])); DEBUG(("\n")); if (os->opcode < 0x01 || os->opcode > 0x10) { error("bad ROP2 0x%x\n", os->opcode); return; } points = (RD_POINT *) xmalloc((os->lines + 1) * sizeof(RD_POINT)); memset(points, 0, (os->lines + 1) * sizeof(RD_POINT)); points[0].x = os->x; points[0].y = os->y; pen.style = pen.width = 0; pen.colour = os->fgcolour; index = 0; data = ((os->lines - 1) / 4) + 1; for (next = 1; (next <= os->lines) && (data < os->datasize); next++) { if ((next - 1) % 4 == 0) flags = os->data[index++]; if (~flags & 0x80) points[next].x = parse_delta(os->data, &data); if (~flags & 0x40) points[next].y = parse_delta(os->data, &data); flags <<= 2; } if (next - 1 == os->lines) ui_polyline(os->opcode - 1, points, os->lines + 1, &pen); else error("polyline parse error\n"); xfree(points); } /* Process an ellipse order */ static void process_ellipse(STREAM s, ELLIPSE_ORDER * os, uint32 present, RD_BOOL delta) { if (present & 0x01) rdp_in_coord(s, &os->left, delta); if (present & 0x02) rdp_in_coord(s, &os->top, delta); if (present & 0x04) rdp_in_coord(s, &os->right, delta); if (present & 0x08) rdp_in_coord(s, &os->bottom, delta); if (present & 0x10) in_uint8(s, os->opcode); if (present & 0x20) in_uint8(s, os->fillmode); if (present & 0x40) rdp_in_colour(s, &os->fgcolour); DEBUG(("ELLIPSE(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,fg=0x%x)\n", os->left, os->top, os->right, os->bottom, os->opcode, os->fillmode, os->fgcolour)); ui_ellipse(os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left, os->bottom - os->top, NULL, 0, os->fgcolour); } /* Process an ellipse2 order */ static void process_ellipse2(STREAM s, ELLIPSE2_ORDER * os, uint32 present, RD_BOOL delta) { BRUSH brush; if (present & 0x0001) rdp_in_coord(s, &os->left, delta); if (present & 0x0002) rdp_in_coord(s, &os->top, delta); if (present & 0x0004) rdp_in_coord(s, &os->right, delta); if (present & 0x0008) rdp_in_coord(s, &os->bottom, delta); if (present & 0x0010) in_uint8(s, os->opcode); if (present & 0x0020) in_uint8(s, os->fillmode); if (present & 0x0040) rdp_in_colour(s, &os->bgcolour); if (present & 0x0080) rdp_in_colour(s, &os->fgcolour); rdp_parse_brush(s, &os->brush, present >> 8); DEBUG(("ELLIPSE2(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,bs=%d,bg=0x%x,fg=0x%x)\n", os->left, os->top, os->right, os->bottom, os->opcode, os->fillmode, os->brush.style, os->bgcolour, os->fgcolour)); setup_brush(&brush, &os->brush); ui_ellipse(os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left, os->bottom - os->top, &brush, os->bgcolour, os->fgcolour); } /* Process a text order */ static void process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, RD_BOOL delta) { int i; BRUSH brush; if (present & 0x000001) in_uint8(s, os->font); if (present & 0x000002) in_uint8(s, os->flags); if (present & 0x000004) in_uint8(s, os->opcode); if (present & 0x000008) in_uint8(s, os->mixmode); if (present & 0x000010) rdp_in_colour(s, &os->fgcolour); if (present & 0x000020) rdp_in_colour(s, &os->bgcolour); if (present & 0x000040) in_uint16_le(s, os->clipleft); if (present & 0x000080) in_uint16_le(s, os->cliptop); if (present & 0x000100) in_uint16_le(s, os->clipright); if (present & 0x000200) in_uint16_le(s, os->clipbottom); if (present & 0x000400) in_uint16_le(s, os->boxleft); if (present & 0x000800) in_uint16_le(s, os->boxtop); if (present & 0x001000) in_uint16_le(s, os->boxright); if (present & 0x002000) in_uint16_le(s, os->boxbottom); rdp_parse_brush(s, &os->brush, present >> 14); if (present & 0x080000) in_uint16_le(s, os->x); if (present & 0x100000) in_uint16_le(s, os->y); if (present & 0x200000) { in_uint8(s, os->length); in_uint8a(s, os->text, os->length); } DEBUG(("TEXT2(x=%d,y=%d,cl=%d,ct=%d,cr=%d,cb=%d,bl=%d,bt=%d,br=%d,bb=%d,bs=%d,bg=0x%x,fg=0x%x,font=%d,fl=0x%x,op=0x%x,mix=%d,n=%d)\n", os->x, os->y, os->clipleft, os->cliptop, os->clipright, os->clipbottom, os->boxleft, os->boxtop, os->boxright, os->boxbottom, os->brush.style, os->bgcolour, os->fgcolour, os->font, os->flags, os->opcode, os->mixmode, os->length)); DEBUG(("Text: ")); for (i = 0; i < os->length; i++) DEBUG(("%02x ", os->text[i])); DEBUG(("\n")); setup_brush(&brush, &os->brush); ui_draw_text(os->font, os->flags, os->opcode - 1, os->mixmode, os->x, os->y, os->clipleft, os->cliptop, os->clipright - os->clipleft, os->clipbottom - os->cliptop, os->boxleft, os->boxtop, os->boxright - os->boxleft, os->boxbottom - os->boxtop, &brush, os->bgcolour, os->fgcolour, os->text, os->length); } /* Process a raw bitmap cache order */ static void process_raw_bmpcache(STREAM s) { RD_HBITMAP bitmap; uint16 cache_idx, bufsize; uint8 cache_id, width, height, bpp, Bpp; uint8 *data, *inverted; int y; in_uint8(s, cache_id); in_uint8s(s, 1); /* pad */ in_uint8(s, width); in_uint8(s, height); in_uint8(s, bpp); Bpp = (bpp + 7) / 8; in_uint16_le(s, bufsize); in_uint16_le(s, cache_idx); in_uint8p(s, data, bufsize); DEBUG(("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx)); inverted = (uint8 *) xmalloc(width * height * Bpp); for (y = 0; y < height; y++) { memcpy(&inverted[(height - y - 1) * (width * Bpp)], &data[y * (width * Bpp)], width * Bpp); } bitmap = ui_create_bitmap(width, height, inverted); xfree(inverted); cache_put_bitmap(cache_id, cache_idx, bitmap); } /* Process a bitmap cache order */ static void process_bmpcache(STREAM s) { RD_HBITMAP bitmap; uint16 cache_idx, size; uint8 cache_id, width, height, bpp, Bpp; uint8 *data, *bmpdata; uint16 bufsize, pad2, row_size, final_size; uint8 pad1; pad2 = row_size = final_size = 0xffff; /* Shut the compiler up */ in_uint8(s, cache_id); in_uint8(s, pad1); /* pad */ in_uint8(s, width); in_uint8(s, height); in_uint8(s, bpp); Bpp = (bpp + 7) / 8; in_uint16_le(s, bufsize); /* bufsize */ in_uint16_le(s, cache_idx); if (g_rdp_version >= RDP_V5) { size = bufsize; } else { /* Begin compressedBitmapData */ in_uint16_le(s, pad2); /* pad */ in_uint16_le(s, size); /* in_uint8s(s, 4); *//* row_size, final_size */ in_uint16_le(s, row_size); in_uint16_le(s, final_size); } in_uint8p(s, data, size); DEBUG(("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d,bpp=%d,size=%d,pad1=%d,bufsize=%d,pad2=%d,rs=%d,fs=%d)\n", width, height, cache_id, cache_idx, bpp, size, pad1, bufsize, pad2, row_size, final_size)); bmpdata = (uint8 *) xmalloc(width * height * Bpp); if (bitmap_decompress(bmpdata, width, height, data, size, Bpp)) { bitmap = ui_create_bitmap(width, height, bmpdata); cache_put_bitmap(cache_id, cache_idx, bitmap); } else { DEBUG(("Failed to decompress bitmap data\n")); } xfree(bmpdata); } /* Process a bitmap cache v2 order */ static void process_bmpcache2(STREAM s, uint16 flags, RD_BOOL compressed) { RD_HBITMAP bitmap; int y; uint8 cache_id, cache_idx_low, width, height, Bpp; uint16 cache_idx, bufsize; uint8 *data, *bmpdata, *bitmap_id; bitmap_id = NULL; /* prevent compiler warning */ cache_id = flags & ID_MASK; Bpp = ((flags & MODE_MASK) >> MODE_SHIFT) - 2; if (flags & PERSIST) { in_uint8p(s, bitmap_id, 8); } if (flags & SQUARE) { in_uint8(s, width); height = width; } else { in_uint8(s, width); in_uint8(s, height); } in_uint16_be(s, bufsize); bufsize &= BUFSIZE_MASK; in_uint8(s, cache_idx); if (cache_idx & LONG_FORMAT) { in_uint8(s, cache_idx_low); cache_idx = ((cache_idx ^ LONG_FORMAT) << 8) + cache_idx_low; } in_uint8p(s, data, bufsize); DEBUG(("BMPCACHE2(compr=%d,flags=%x,cx=%d,cy=%d,id=%d,idx=%d,Bpp=%d,bs=%d)\n", compressed, flags, width, height, cache_id, cache_idx, Bpp, bufsize)); bmpdata = (uint8 *) xmalloc(width * height * Bpp); if (compressed) { if (!bitmap_decompress(bmpdata, width, height, data, bufsize, Bpp)) { DEBUG(("Failed to decompress bitmap data\n")); xfree(bmpdata); return; } } else { for (y = 0; y < height; y++) memcpy(&bmpdata[(height - y - 1) * (width * Bpp)], &data[y * (width * Bpp)], width * Bpp); } bitmap = ui_create_bitmap(width, height, bmpdata); if (bitmap) { cache_put_bitmap(cache_id, cache_idx, bitmap); if (flags & PERSIST) pstcache_save_bitmap(cache_id, cache_idx, bitmap_id, width, height, width * height * Bpp, bmpdata); } else { DEBUG(("process_bmpcache2: ui_create_bitmap failed\n")); } xfree(bmpdata); } /* Process a colourmap cache order */ static void process_colcache(STREAM s) { COLOURENTRY *entry; COLOURMAP map; RD_HCOLOURMAP hmap; uint8 cache_id; int i; in_uint8(s, cache_id); in_uint16_le(s, map.ncolours); map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours); for (i = 0; i < map.ncolours; i++) { entry = &map.colours[i]; in_uint8(s, entry->blue); in_uint8(s, entry->green); in_uint8(s, entry->red); in_uint8s(s, 1); /* pad */ } DEBUG(("COLCACHE(id=%d,n=%d)\n", cache_id, map.ncolours)); hmap = ui_create_colourmap(&map); if (cache_id) ui_set_colourmap(hmap); xfree(map.colours); } /* Process a font cache order */ static void process_fontcache(STREAM s) { RD_HGLYPH bitmap; uint8 font, nglyphs; uint16 character, offset, baseline, width, height; int i, datasize; uint8 *data; in_uint8(s, font); in_uint8(s, nglyphs); DEBUG(("FONTCACHE(font=%d,n=%d)\n", font, nglyphs)); for (i = 0; i < nglyphs; i++) { in_uint16_le(s, character); in_uint16_le(s, offset); in_uint16_le(s, baseline); in_uint16_le(s, width); in_uint16_le(s, height); datasize = (height * ((width + 7) / 8) + 3) & ~3; in_uint8p(s, data, datasize); bitmap = ui_create_glyph(width, height, data); cache_put_font(font, character, offset, baseline, width, height, bitmap); } } static void process_compressed_8x8_brush_data(uint8 * in, uint8 * out, int Bpp) { int x, y, pal_index, in_index, shift, do2, i; uint8 *pal; in_index = 0; pal = in + 16; /* read it bottom up */ for (y = 7; y >= 0; y--) { /* 2 bytes per row */ x = 0; for (do2 = 0; do2 < 2; do2++) { /* 4 pixels per byte */ shift = 6; while (shift >= 0) { pal_index = (in[in_index] >> shift) & 3; /* size of palette entries depends on Bpp */ for (i = 0; i < Bpp; i++) { out[(y * 8 + x) * Bpp + i] = pal[pal_index * Bpp + i]; } x++; shift -= 2; } in_index++; } } } /* Process a brush cache order */ static void process_brushcache(STREAM s, uint16 flags) { BRUSHDATA brush_data; uint8 cache_idx, colour_code, width, height, size, type; uint8 *comp_brush; int index; int Bpp; in_uint8(s, cache_idx); in_uint8(s, colour_code); in_uint8(s, width); in_uint8(s, height); in_uint8(s, type); /* type, 0x8x = cached */ in_uint8(s, size); DEBUG(("BRUSHCACHE(idx=%d,wd=%d,ht=%d,sz=%d)\n", cache_idx, width, height, size)); if ((width == 8) && (height == 8)) { if (colour_code == 1) { brush_data.colour_code = 1; brush_data.data_size = 8; brush_data.data = xmalloc(8); if (size == 8) { /* read it bottom up */ for (index = 7; index >= 0; index--) { in_uint8(s, brush_data.data[index]); } } else { warning("incompatible brush, colour_code %d size %d\n", colour_code, size); } cache_put_brush_data(1, cache_idx, &brush_data); } else if ((colour_code >= 3) && (colour_code <= 6)) { Bpp = colour_code - 2; brush_data.colour_code = colour_code; brush_data.data_size = 8 * 8 * Bpp; brush_data.data = xmalloc(8 * 8 * Bpp); if (size == 16 + 4 * Bpp) { in_uint8p(s, comp_brush, 16 + 4 * Bpp); process_compressed_8x8_brush_data(comp_brush, brush_data.data, Bpp); } else { in_uint8a(s, brush_data.data, 8 * 8 * Bpp); } cache_put_brush_data(colour_code, cache_idx, &brush_data); } else { warning("incompatible brush, colour_code %d size %d\n", colour_code, size); } } else { warning("incompatible brush, width height %d %d\n", width, height); } } /* Process a secondary order */ static void process_secondary_order(STREAM s) { /* The length isn't calculated correctly by the server. * For very compact orders the length becomes negative * so a signed integer must be used. */ uint16 length; uint16 flags; uint8 type; uint8 *next_order; in_uint16_le(s, length); in_uint16_le(s, flags); /* used by bmpcache2 */ in_uint8(s, type); next_order = s->p + (sint16) length + 7; switch (type) { case RDP_ORDER_RAW_BMPCACHE: process_raw_bmpcache(s); break; case RDP_ORDER_COLCACHE: process_colcache(s); break; case RDP_ORDER_BMPCACHE: process_bmpcache(s); break; case RDP_ORDER_FONTCACHE: process_fontcache(s); break; case RDP_ORDER_RAW_BMPCACHE2: process_bmpcache2(s, flags, False); /* uncompressed */ break; case RDP_ORDER_BMPCACHE2: process_bmpcache2(s, flags, True); /* compressed */ break; case RDP_ORDER_BRUSHCACHE: process_brushcache(s, flags); break; default: unimpl("secondary order %d\n", type); } s->p = next_order; } /* Process an order PDU */ void process_orders(STREAM s, uint16 num_orders) { RDP_ORDER_STATE *os = &g_order_state; uint32 present; uint8 order_flags; int size, processed = 0; RD_BOOL delta; while (processed < num_orders) { in_uint8(s, order_flags); if (!(order_flags & RDP_ORDER_STANDARD)) { error("order parsing failed\n"); break; } if (order_flags & RDP_ORDER_SECONDARY) { process_secondary_order(s); } else { if (order_flags & RDP_ORDER_CHANGE) { in_uint8(s, os->order_type); } switch (os->order_type) { case RDP_ORDER_TRIBLT: case RDP_ORDER_TEXT2: size = 3; break; case RDP_ORDER_PATBLT: case RDP_ORDER_MEMBLT: case RDP_ORDER_LINE: case RDP_ORDER_POLYGON2: case RDP_ORDER_ELLIPSE2: size = 2; break; default: size = 1; } rdp_in_present(s, &present, order_flags, size); if (order_flags & RDP_ORDER_BOUNDS) { if (!(order_flags & RDP_ORDER_LASTBOUNDS)) rdp_parse_bounds(s, &os->bounds); ui_set_clip(os->bounds.left, os->bounds.top, os->bounds.right - os->bounds.left + 1, os->bounds.bottom - os->bounds.top + 1); } delta = order_flags & RDP_ORDER_DELTA; switch (os->order_type) { case RDP_ORDER_DESTBLT: process_destblt(s, &os->destblt, present, delta); break; case RDP_ORDER_PATBLT: process_patblt(s, &os->patblt, present, delta); break; case RDP_ORDER_SCREENBLT: process_screenblt(s, &os->screenblt, present, delta); break; case RDP_ORDER_LINE: process_line(s, &os->line, present, delta); break; case RDP_ORDER_RECT: process_rect(s, &os->rect, present, delta); break; case RDP_ORDER_DESKSAVE: process_desksave(s, &os->desksave, present, delta); break; case RDP_ORDER_MEMBLT: process_memblt(s, &os->memblt, present, delta); break; case RDP_ORDER_TRIBLT: process_triblt(s, &os->triblt, present, delta); break; case RDP_ORDER_POLYGON: process_polygon(s, &os->polygon, present, delta); break; case RDP_ORDER_POLYGON2: process_polygon2(s, &os->polygon2, present, delta); break; case RDP_ORDER_POLYLINE: process_polyline(s, &os->polyline, present, delta); break; case RDP_ORDER_ELLIPSE: process_ellipse(s, &os->ellipse, present, delta); break; case RDP_ORDER_ELLIPSE2: process_ellipse2(s, &os->ellipse2, present, delta); break; case RDP_ORDER_TEXT2: process_text2(s, &os->text2, present, delta); break; default: unimpl("order %d\n", os->order_type); return; } if (order_flags & RDP_ORDER_BOUNDS) ui_reset_clip(); } processed++; } #if 0 /* not true when RDP_COMPRESSION is set */ if (s->p != g_next_packet) error("%d bytes remaining\n", (int) (g_next_packet - s->p)); #endif } /* Reset order state */ void reset_order_state(void) { memset(&g_order_state, 0, sizeof(g_order_state)); g_order_state.order_type = RDP_ORDER_PATBLT; } rdesktop-1.8.3/parallel.c0000664000770100510440000001056211551302500014231 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ #define MAX_PARALLEL_DEVICES 1 #define FILE_DEVICE_PARALLEL 0x22 #define IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x0c #include "rdesktop.h" #include #include #include #include #if defined(__linux__) #include #endif extern RDPDR_DEVICE g_rdpdr_device[]; /* Enumeration of devices from rdesktop.c */ /* returns numer of units found and initialized. */ /* optarg looks like ':LPT1=/dev/lp0' */ /* when it arrives to this function. */ int parallel_enum_devices(uint32 * id, char *optarg) { PARALLEL_DEVICE *ppar_info; char *pos = optarg; char *pos2; int count = 0; /* skip the first colon */ optarg++; while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES) { ppar_info = (PARALLEL_DEVICE *) xmalloc(sizeof(PARALLEL_DEVICE)); pos2 = next_arg(optarg, '='); strcpy(g_rdpdr_device[*id].name, optarg); toupper_str(g_rdpdr_device[*id].name); g_rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1); strcpy(g_rdpdr_device[*id].local_path, pos2); printf("PARALLEL %s to %s\n", optarg, pos2); /* set device type */ g_rdpdr_device[*id].device_type = DEVICE_TYPE_PARALLEL; g_rdpdr_device[*id].pdevice_data = (void *) ppar_info; g_rdpdr_device[*id].handle = 0; count++; (*id)++; optarg = pos; } return count; } static RD_NTSTATUS parallel_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags, char *filename, RD_NTHANDLE * handle) { int parallel_fd; parallel_fd = open(g_rdpdr_device[device_id].local_path, O_RDWR); if (parallel_fd == -1) { perror("open"); return RD_STATUS_ACCESS_DENIED; } /* all read and writes should be non blocking */ if (fcntl(parallel_fd, F_SETFL, O_NONBLOCK) == -1) perror("fcntl"); #if defined(LPABORT) /* Retry on errors */ ioctl(parallel_fd, LPABORT, (int) 1); #endif g_rdpdr_device[device_id].handle = parallel_fd; *handle = parallel_fd; return RD_STATUS_SUCCESS; } static RD_NTSTATUS parallel_close(RD_NTHANDLE handle) { int i = get_device_index(handle); if (i >= 0) g_rdpdr_device[i].handle = 0; close(handle); return RD_STATUS_SUCCESS; } static RD_NTSTATUS parallel_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { *result = read(handle, data, length); return RD_STATUS_SUCCESS; } static RD_NTSTATUS parallel_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { int rc = RD_STATUS_SUCCESS; int n = write(handle, data, length); if (n < 0) { #if defined(LPGETSTATUS) int status; #endif *result = 0; switch (errno) { case EAGAIN: rc = RD_STATUS_DEVICE_OFF_LINE; case ENOSPC: rc = RD_STATUS_DEVICE_PAPER_EMPTY; case EIO: rc = RD_STATUS_DEVICE_OFF_LINE; default: rc = RD_STATUS_DEVICE_POWERED_OFF; } #if defined(LPGETSTATUS) if (ioctl(handle, LPGETSTATUS, &status) == 0) { /* coming soon: take care for the printer status */ printf("parallel_write: status = %d, errno = %d\n", status, errno); } #endif } *result = n; return rc; } static RD_NTSTATUS parallel_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) { if ((request >> 16) != FILE_DEVICE_PARALLEL) return RD_STATUS_INVALID_PARAMETER; /* extract operation */ request >>= 2; request &= 0xfff; printf("PARALLEL IOCTL %d: ", request); switch (request) { case IOCTL_PAR_QUERY_RAW_DEVICE_ID: default: printf("\n"); unimpl("UNKNOWN IOCTL %d\n", request); } return RD_STATUS_SUCCESS; } DEVICE_FNS parallel_fns = { parallel_create, parallel_close, parallel_read, parallel_write, parallel_device_control }; rdesktop-1.8.3/printer.c0000664000770100510440000001026212306031202014112 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ #include "rdesktop.h" extern RDPDR_DEVICE g_rdpdr_device[]; static PRINTER * get_printer_data(RD_NTHANDLE handle) { int index; for (index = 0; index < RDPDR_MAX_DEVICES; index++) { if (handle == g_rdpdr_device[index].handle) return (PRINTER *) g_rdpdr_device[index].pdevice_data; } return NULL; } int printer_enum_devices(uint32 * id, char *optarg) { PRINTER *pprinter_data; char *pos = optarg; char *pos2; int count = 0; int already = 0; /* we need to know how many printers we've already set up supplied from other -r flags than this one. */ while (count < *id) { if (g_rdpdr_device[count].device_type == DEVICE_TYPE_PRINTER) already++; count++; } count = 0; if (*optarg == ':') optarg++; while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES) { pprinter_data = (PRINTER *) xmalloc(sizeof(PRINTER)); strcpy(g_rdpdr_device[*id].name, "PRN"); strcat(g_rdpdr_device[*id].name, l_to_a(already + count + 1, 10)); /* first printer is set as default printer */ if ((already + count) == 0) pprinter_data->default_printer = True; else pprinter_data->default_printer = False; pos2 = next_arg(optarg, '='); if (*optarg == (char) 0x00) pprinter_data->printer = "mydeskjet"; /* set default */ else { pprinter_data->printer = xmalloc(strlen(optarg) + 1); strcpy(pprinter_data->printer, optarg); } if (!pos2 || (*pos2 == (char) 0x00)) pprinter_data->driver = "MS Publisher Imagesetter"; /* no printer driver supplied set default */ else { pprinter_data->driver = xmalloc(strlen(pos2) + 1); strcpy(pprinter_data->driver, pos2); } printf("PRINTER %s to %s driver %s\n", g_rdpdr_device[*id].name, pprinter_data->printer, pprinter_data->driver); g_rdpdr_device[*id].device_type = DEVICE_TYPE_PRINTER; g_rdpdr_device[*id].pdevice_data = (void *) pprinter_data; count++; (*id)++; optarg = pos; } return count; } static RD_NTSTATUS printer_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags, char *filename, RD_NTHANDLE * handle) { char cmd[256]; PRINTER *pprinter_data; pprinter_data = (PRINTER *) g_rdpdr_device[device_id].pdevice_data; /* default printer name use default printer queue as well in unix */ if (strncmp(pprinter_data->printer, "mydeskjet", strlen(pprinter_data->printer)) == 0) { pprinter_data->printer_fp = popen("lpr", "w"); } else { sprintf(cmd, "lpr -P %s", pprinter_data->printer); pprinter_data->printer_fp = popen(cmd, "w"); } g_rdpdr_device[device_id].handle = fileno(pprinter_data->printer_fp); *handle = g_rdpdr_device[device_id].handle; return RD_STATUS_SUCCESS; } static RD_NTSTATUS printer_close(RD_NTHANDLE handle) { int i = get_device_index(handle); if (i >= 0) { PRINTER *pprinter_data = g_rdpdr_device[i].pdevice_data; if (pprinter_data) pclose(pprinter_data->printer_fp); g_rdpdr_device[i].handle = 0; } return RD_STATUS_SUCCESS; } static RD_NTSTATUS printer_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { PRINTER *pprinter_data; pprinter_data = get_printer_data(handle); *result = length * fwrite(data, length, 1, pprinter_data->printer_fp); if (ferror(pprinter_data->printer_fp)) { *result = 0; return RD_STATUS_INVALID_HANDLE; } return RD_STATUS_SUCCESS; } DEVICE_FNS printer_fns = { printer_create, printer_close, NULL, /* read */ printer_write, NULL /* device_control */ }; rdesktop-1.8.3/printercache.c0000664000770100510440000001621512252340726015120 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Entrypoint and utility functions Copyright (C) Matthew Chapman 1999-2008 Copyright (C) Jeroen Meijer 2003-2008 Copyright (C) Henrik Andersson 2013 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 3 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, see . */ /* According to the W2K RDP Printer Redirection WhitePaper, a data * blob is sent to the client after the configuration of the printer * is changed at the server. * * This data blob is saved to the registry. The client returns this * data blob in a new session with the printer announce data. * The data is not interpreted by the client. */ #include #include #include #include #include #include #include "rdesktop.h" static RD_BOOL printercache_mkdir(char *base, char *printer) { char *path; path = (char *) xmalloc(strlen(base) + sizeof("/.rdesktop/rdpdr/") + strlen(printer) + 1); sprintf(path, "%s/.rdesktop", base); if ((mkdir(path, 0700) == -1) && errno != EEXIST) { perror(path); xfree(path); return False; } strcat(path, "/rdpdr"); if ((mkdir(path, 0700) == -1) && errno != EEXIST) { perror(path); xfree(path); return False; } strcat(path, "/"); strcat(path, printer); if ((mkdir(path, 0700) == -1) && errno != EEXIST) { perror(path); xfree(path); return False; } xfree(path); return True; } static RD_BOOL printercache_unlink_blob(char *printer) { char *path; char *home; if (printer == NULL) return False; home = getenv("HOME"); if (home == NULL) return False; path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer) + sizeof("/AutoPrinterCacheData") + 1); sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer); if (unlink(path) < 0) { xfree(path); return False; } sprintf(path, "%s/.rdesktop/rdpdr/%s", home, printer); if (rmdir(path) < 0) { xfree(path); return False; } xfree(path); return True; } static RD_BOOL printercache_rename_blob(char *printer, char *new_printer) { char *printer_path; char *new_printer_path; int printer_maxlen; char *home; if (printer == NULL) return False; home = getenv("HOME"); if (home == NULL) return False; printer_maxlen = (strlen(printer) > strlen(new_printer) ? strlen(printer) : strlen(new_printer)) + strlen(home) + sizeof("/.rdesktop/rdpdr/") + 1; printer_path = (char *) xmalloc(printer_maxlen); new_printer_path = (char *) xmalloc(printer_maxlen); sprintf(printer_path, "%s/.rdesktop/rdpdr/%s", home, printer); sprintf(new_printer_path, "%s/.rdesktop/rdpdr/%s", home, new_printer); printf("%s,%s\n", printer_path, new_printer_path); if (rename(printer_path, new_printer_path) < 0) { xfree(printer_path); xfree(new_printer_path); return False; } xfree(printer_path); xfree(new_printer_path); return True; } int printercache_load_blob(char *printer_name, uint8 ** data) { char *home, *path; struct stat st; int fd, length; if (printer_name == NULL) return 0; *data = NULL; home = getenv("HOME"); if (home == NULL) return 0; path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) + sizeof("/AutoPrinterCacheData") + 1); sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name); fd = open(path, O_RDONLY); if (fd == -1) { xfree(path); return 0; } if (fstat(fd, &st)) { xfree(path); return 0; } *data = (uint8 *) xmalloc(st.st_size); length = read(fd, *data, st.st_size); close(fd); xfree(path); return length; } static void printercache_save_blob(char *printer_name, uint8 * data, uint32 length) { char *home, *path; int fd; if (printer_name == NULL) return; home = getenv("HOME"); if (home == NULL) return; if (!printercache_mkdir(home, printer_name)) return; path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) + sizeof("/AutoPrinterCacheData") + 1); sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name); fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd == -1) { perror(path); xfree(path); return; } if (write(fd, data, length) != length) { perror(path); unlink(path); } close(fd); xfree(path); } void printercache_process(STREAM s) { uint32 type, printer_length, driver_length, printer_unicode_length, blob_length; char device_name[9], *printer, *driver; printer = driver = NULL; in_uint32_le(s, type); switch (type) { case 4: /* rename item */ in_uint8(s, printer_length); in_uint8s(s, 0x3); /* padding */ in_uint8(s, driver_length); in_uint8s(s, 0x3); /* padding */ /* NOTE - 'driver' doesn't contain driver, it contains the new printer name */ rdp_in_unistr(s, printer_length, &printer, &printer_length); rdp_in_unistr(s, driver_length, &driver, &driver_length); if (printer != NULL && driver != NULL) printercache_rename_blob(printer, driver); free(printer); free(driver); break; case 3: /* delete item */ in_uint8(s, printer_unicode_length); in_uint8s(s, 0x3); /* padding */ rdp_in_unistr(s, printer_unicode_length, &printer, &printer_unicode_length); if (printer) printercache_unlink_blob(printer); free(printer); break; case 2: /* save printer data */ in_uint32_le(s, printer_unicode_length); in_uint32_le(s, blob_length); if (printer_unicode_length < 2 * 255) { rdp_in_unistr(s, printer_unicode_length, &printer, &printer_unicode_length); if (printer) printercache_save_blob(printer, s->p, blob_length); free(printer); } break; case 1: /* save device data */ in_uint8a(s, device_name, 5); /* get LPTx/COMx name */ /* need to fetch this data so that we can get the length of the packet to store. */ in_uint8s(s, 0x2); /* ??? */ in_uint8s(s, 0x2) /* pad?? */ in_uint32_be(s, driver_length); in_uint32_be(s, printer_length); in_uint8s(s, 0x7) /* pad?? */ /* next is driver in unicode */ /* next is printer in unicode */ /* TODO: figure out how to use this information when reconnecting */ /* actually - all we need to store is the driver and printer */ /* and figure out what the first word is. */ /* rewind stream so that we can save this blob */ /* length is driver_length + printer_length + 19 */ /* rewind stream */ s->p = s->p - 19; printercache_save_blob(device_name, s->p, driver_length + printer_length + 19); break; default: unimpl("RDPDR Printer Cache Packet Type: %d\n", type); break; } } rdesktop-1.8.3/pstcache.c0000664000770100510440000001232211551302500014223 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Persistent Bitmap Cache routines Copyright (C) Jeroen Meijer 2004-2008 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 3 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, see . */ #include "rdesktop.h" #define MAX_CELL_SIZE 0x1000 /* pixels */ #define IS_PERSISTENT(id) (id < 8 && g_pstcache_fd[id] > 0) extern int g_server_depth; extern RD_BOOL g_bitmap_cache; extern RD_BOOL g_bitmap_cache_persist_enable; extern RD_BOOL g_bitmap_cache_precache; int g_pstcache_fd[8]; int g_pstcache_Bpp; RD_BOOL g_pstcache_enumerated = False; uint8 zero_key[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* Update mru stamp/index for a bitmap */ void pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp) { int fd; if (!IS_PERSISTENT(cache_id) || cache_idx >= BMPCACHE2_NUM_PSTCELLS) return; fd = g_pstcache_fd[cache_id]; rd_lseek_file(fd, 12 + cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER))); rd_write_file(fd, &stamp, sizeof(stamp)); } /* Load a bitmap from the persistent cache */ RD_BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx) { uint8 *celldata; int fd; CELLHEADER cellhdr; RD_HBITMAP bitmap; if (!g_bitmap_cache_persist_enable) return False; if (!IS_PERSISTENT(cache_id) || cache_idx >= BMPCACHE2_NUM_PSTCELLS) return False; fd = g_pstcache_fd[cache_id]; rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER))); rd_read_file(fd, &cellhdr, sizeof(CELLHEADER)); celldata = (uint8 *) xmalloc(cellhdr.length); rd_read_file(fd, celldata, cellhdr.length); bitmap = ui_create_bitmap(cellhdr.width, cellhdr.height, celldata); DEBUG(("Load bitmap from disk: id=%d, idx=%d, bmp=%p)\n", cache_id, cache_idx, bitmap)); cache_put_bitmap(cache_id, cache_idx, bitmap); xfree(celldata); return True; } /* Store a bitmap in the persistent cache */ RD_BOOL pstcache_save_bitmap(uint8 cache_id, uint16 cache_idx, uint8 * key, uint8 width, uint8 height, uint16 length, uint8 * data) { int fd; CELLHEADER cellhdr; if (!IS_PERSISTENT(cache_id) || cache_idx >= BMPCACHE2_NUM_PSTCELLS) return False; memcpy(cellhdr.key, key, sizeof(HASH_KEY)); cellhdr.width = width; cellhdr.height = height; cellhdr.length = length; cellhdr.stamp = 0; fd = g_pstcache_fd[cache_id]; rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER))); rd_write_file(fd, &cellhdr, sizeof(CELLHEADER)); rd_write_file(fd, data, length); return True; } /* List the bitmap keys from the persistent cache file */ int pstcache_enumerate(uint8 id, HASH_KEY * keylist) { int fd, n; uint16 idx; sint16 mru_idx[0xa00]; uint32 mru_stamp[0xa00]; CELLHEADER cellhdr; if (!(g_bitmap_cache && g_bitmap_cache_persist_enable && IS_PERSISTENT(id))) return 0; /* The server disconnects if the bitmap cache content is sent more than once */ if (g_pstcache_enumerated) return 0; DEBUG_RDP5(("Persistent bitmap cache enumeration... ")); for (idx = 0; idx < BMPCACHE2_NUM_PSTCELLS; idx++) { fd = g_pstcache_fd[id]; rd_lseek_file(fd, idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER))); if (rd_read_file(fd, &cellhdr, sizeof(CELLHEADER)) <= 0) break; if (memcmp(cellhdr.key, zero_key, sizeof(HASH_KEY)) != 0) { memcpy(keylist[idx], cellhdr.key, sizeof(HASH_KEY)); /* Pre-cache (not possible for 8 bit colour depth cause it needs a colourmap) */ if (g_bitmap_cache_precache && cellhdr.stamp && g_server_depth > 8) pstcache_load_bitmap(id, idx); /* Sort by stamp */ for (n = idx; n > 0 && cellhdr.stamp < mru_stamp[n - 1]; n--) { mru_idx[n] = mru_idx[n - 1]; mru_stamp[n] = mru_stamp[n - 1]; } mru_idx[n] = idx; mru_stamp[n] = cellhdr.stamp; } else { break; } } DEBUG_RDP5(("%d cached bitmaps.\n", idx)); cache_rebuild_bmpcache_linked_list(id, mru_idx, idx); g_pstcache_enumerated = True; return idx; } /* initialise the persistent bitmap cache */ RD_BOOL pstcache_init(uint8 cache_id) { int fd; char filename[256]; if (g_pstcache_enumerated) return True; g_pstcache_fd[cache_id] = 0; if (!(g_bitmap_cache && g_bitmap_cache_persist_enable)) return False; if (!rd_pstcache_mkdir()) { DEBUG(("failed to get/make cache directory!\n")); return False; } g_pstcache_Bpp = (g_server_depth + 7) / 8; sprintf(filename, "cache/pstcache_%d_%d", cache_id, g_pstcache_Bpp); DEBUG(("persistent bitmap cache file: %s\n", filename)); fd = rd_open_file(filename); if (fd == -1) return False; if (!rd_lock_file(fd, 0, 0)) { warning("Persistent bitmap caching is disabled. (The file is already in use)\n"); rd_close_file(fd); return False; } g_pstcache_fd[cache_id] = fd; return True; } rdesktop-1.8.3/rdesktop.c0000664000770100510440000012320512404306606014300 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Entrypoint and utility functions Copyright (C) Matthew Chapman 1999-2008 Copyright 2002-2011 Peter Astrand for Cendio AB Copyright 2010-2014 Henrik Andersson for Cendio AB 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 3 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, see . */ #include /* va_list va_start va_end */ #include /* read close getuid getgid getpid getppid gethostname */ #include /* open */ #include /* getpwuid */ #include /* tcgetattr tcsetattr */ #include /* stat */ #include /* gettimeofday */ #include /* times */ #include /* toupper */ #include #include #include #include "rdesktop.h" #ifdef HAVE_LOCALE_H #include #endif #ifdef HAVE_ICONV #ifdef HAVE_LANGINFO_H #include #endif #endif #ifdef EGD_SOCKET #include #include /* socket connect */ #include /* sockaddr_un */ #endif #include "ssl.h" /* Reconnect timeout based on approxiamted cookie life-time */ #define RECONNECT_TIMEOUT (3600+600) #define RDESKTOP_LICENSE_STORE "/.local/share/rdesktop/licenses" uint8 g_static_rdesktop_salt_16[16] = { 0xb8, 0x82, 0x29, 0x31, 0xc5, 0x39, 0xd9, 0x44, 0x54, 0x15, 0x5e, 0x14, 0x71, 0x38, 0xd5, 0x4d }; char g_title[64] = ""; char *g_username; char g_password[64] = ""; char g_hostname[16] = ""; char g_keymapname[PATH_MAX] = ""; unsigned int g_keylayout = 0x409; /* Defaults to US keyboard layout */ int g_keyboard_type = 0x4; /* Defaults to US keyboard layout */ int g_keyboard_subtype = 0x0; /* Defaults to US keyboard layout */ int g_keyboard_functionkeys = 0xc; /* Defaults to US keyboard layout */ int g_sizeopt = 0; /* If non-zero, a special size has been requested. If 1, the geometry will be fetched from _NET_WORKAREA. If negative, absolute value specifies the percent of the whole screen. */ int g_width = 800; int g_height = 600; int g_xpos = 0; int g_ypos = 0; int g_pos = 0; /* 0 position unspecified, 1 specified, 2 xpos neg, 4 ypos neg */ extern int g_tcp_port_rdp; int g_server_depth = -1; int g_win_button_size = 0; /* If zero, disable single app mode */ RD_BOOL g_network_error = False; RD_BOOL g_bitmap_compression = True; RD_BOOL g_sendmotion = True; RD_BOOL g_bitmap_cache = True; RD_BOOL g_bitmap_cache_persist_enable = False; RD_BOOL g_bitmap_cache_precache = True; RD_BOOL g_use_ctrl = True; RD_BOOL g_encryption = True; RD_BOOL g_encryption_initial = True; RD_BOOL g_packet_encryption = True; RD_BOOL g_desktop_save = True; /* desktop save order */ RD_BOOL g_polygon_ellipse_orders = True; /* polygon / ellipse orders */ RD_BOOL g_fullscreen = False; RD_BOOL g_grab_keyboard = True; RD_BOOL g_hide_decorations = False; RDP_VERSION g_rdp_version = RDP_V5; /* Default to version 5 */ RD_BOOL g_rdpclip = True; RD_BOOL g_console_session = False; RD_BOOL g_numlock_sync = False; RD_BOOL g_lspci_enabled = False; RD_BOOL g_owncolmap = False; RD_BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */ RD_BOOL g_seamless_rdp = False; RD_BOOL g_use_password_as_pin = False; char g_seamless_shell[512]; char g_seamless_spawn_cmd[512]; RD_BOOL g_seamless_persistent_mode = True; RD_BOOL g_user_quit = False; uint32 g_embed_wnd; uint32 g_rdp5_performanceflags = RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS | RDP5_NO_CURSOR_SHADOW; /* Session Directory redirection */ RD_BOOL g_redirect = False; char *g_redirect_server; uint32 g_redirect_server_len; char *g_redirect_domain; uint32 g_redirect_domain_len; char *g_redirect_username; uint32 g_redirect_username_len; uint8 *g_redirect_lb_info; uint32 g_redirect_lb_info_len; uint8 *g_redirect_cookie; uint32 g_redirect_cookie_len; uint32 g_redirect_flags = 0; uint32 g_redirect_session_id = 0; uint32 g_reconnect_logonid = 0; char g_reconnect_random[16]; time_t g_reconnect_random_ts; RD_BOOL g_has_reconnect_random = False; RD_BOOL g_reconnect_loop = False; uint8 g_client_random[SEC_RANDOM_SIZE]; RD_BOOL g_pending_resize = False; #ifdef WITH_RDPSND RD_BOOL g_rdpsnd = False; #endif #ifdef HAVE_ICONV char g_codepage[16] = ""; #endif char *g_sc_csp_name = NULL; /* Smartcard CSP name */ char *g_sc_reader_name = NULL; char *g_sc_card_name = NULL; char *g_sc_container_name = NULL; extern RDPDR_DEVICE g_rdpdr_device[]; extern uint32 g_num_devices; extern char *g_rdpdr_clientname; #ifdef RDP2VNC extern int rfb_port; extern int defer_time; void rdp2vnc_connect(char *server, uint32 flags, char *domain, char *password, char *shell, char *directory); #endif /* Display usage information */ static void usage(char *program) { fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n"); fprintf(stderr, "Version " PACKAGE_VERSION ". Copyright (C) 1999-2011 Matthew Chapman et al.\n"); fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n"); fprintf(stderr, "Usage: %s [options] server[:port]\n", program); #ifdef RDP2VNC fprintf(stderr, " -V: vnc port\n"); fprintf(stderr, " -Q: defer time (ms)\n"); #endif fprintf(stderr, " -u: user name\n"); fprintf(stderr, " -d: domain\n"); fprintf(stderr, " -s: shell / seamless application to start remotly\n"); fprintf(stderr, " -c: working directory\n"); fprintf(stderr, " -p: password (- to prompt)\n"); fprintf(stderr, " -n: client hostname\n"); fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n"); fprintf(stderr, " -g: desktop geometry (WxH)\n"); #ifdef WITH_SCARD fprintf(stderr, " -i: enables smartcard authentication, password is used as pin\n"); #endif fprintf(stderr, " -f: full-screen mode\n"); fprintf(stderr, " -b: force bitmap updates\n"); #ifdef HAVE_ICONV fprintf(stderr, " -L: local codepage\n"); #endif fprintf(stderr, " -A: path to SeamlessRDP shell, this enables SeamlessRDP mode\n"); fprintf(stderr, " -B: use BackingStore of X-server (if available)\n"); fprintf(stderr, " -e: disable encryption (French TS)\n"); fprintf(stderr, " -E: disable encryption from client to server\n"); fprintf(stderr, " -m: do not send motion events\n"); fprintf(stderr, " -C: use private colour map\n"); fprintf(stderr, " -D: hide window manager decorations\n"); fprintf(stderr, " -K: keep window manager key bindings\n"); fprintf(stderr, " -S: caption button size (single application mode)\n"); fprintf(stderr, " -T: window title\n"); fprintf(stderr, " -t: disable use of remote ctrl\n"); fprintf(stderr, " -N: enable numlock syncronization\n"); fprintf(stderr, " -X: embed into another window with a given id.\n"); fprintf(stderr, " -a: connection colour depth\n"); fprintf(stderr, " -z: enable rdp compression\n"); fprintf(stderr, " -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n"); fprintf(stderr, " -P: use persistent bitmap caching\n"); fprintf(stderr, " -r: enable specified device redirection (this flag can be repeated)\n"); fprintf(stderr, " '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n"); fprintf(stderr, " or COM1=/dev/ttyS0,COM2=/dev/ttyS1\n"); fprintf(stderr, " '-r disk:floppy=/mnt/floppy': enable redirection of /mnt/floppy to 'floppy' share\n"); fprintf(stderr, " or 'floppy=/mnt/floppy,cdrom=/mnt/cdrom'\n"); fprintf(stderr, " '-r clientname=': Set the client name displayed\n"); fprintf(stderr, " for redirected disks\n"); fprintf(stderr, " '-r lptport:LPT1=/dev/lp0': enable parallel redirection of /dev/lp0 to LPT1\n"); fprintf(stderr, " or LPT1=/dev/lp0,LPT2=/dev/lp1\n"); fprintf(stderr, " '-r printer:mydeskjet': enable printer redirection\n"); fprintf(stderr, " or mydeskjet=\"HP LaserJet IIIP\" to enter server driver as well\n"); #ifdef WITH_RDPSND fprintf(stderr, " '-r sound:[local[:driver[:device]]|off|remote]': enable sound redirection\n"); fprintf(stderr, " remote would leave sound on server\n"); fprintf(stderr, " available drivers for 'local':\n"); rdpsnd_show_help(); #endif fprintf(stderr, " '-r clipboard:[off|PRIMARYCLIPBOARD|CLIPBOARD]': enable clipboard\n"); fprintf(stderr, " redirection.\n"); fprintf(stderr, " 'PRIMARYCLIPBOARD' looks at both PRIMARY and CLIPBOARD\n"); fprintf(stderr, " when sending data to server.\n"); fprintf(stderr, " 'CLIPBOARD' looks at only CLIPBOARD.\n"); #ifdef WITH_SCARD fprintf(stderr, " '-r scard[:\"Scard Name\"=\"Alias Name[;Vendor Name]\"[,...]]\n"); fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0\"\n"); fprintf(stderr, " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n"); fprintf(stderr, " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n"); fprintf(stderr, " example: -r scard:\"eToken PRO 00 00\"=\"AKS ifdh 0;AKS\"\n"); fprintf(stderr, " \"eToken PRO 00 00\" -> Device in Linux/Unix enviroment\n"); fprintf(stderr, " \"AKS ifdh 0\" -> Device shown in Windows enviroment \n"); fprintf(stderr, " \"AKS\" -> Device vendor name \n"); #endif fprintf(stderr, " -0: attach to console\n"); fprintf(stderr, " -4: use RDP version 4\n"); fprintf(stderr, " -5: use RDP version 5 (default)\n"); #ifdef WITH_SCARD fprintf(stderr, " -o: name=value: Adds an additional option to rdesktop.\n"); fprintf(stderr, " sc-csp-name Specifies the Crypto Service Provider name which\n"); fprintf(stderr, " is used to authenticate the user by smartcard\n"); fprintf(stderr, " sc-container-name Specifies the container name, this is usally the username\n"); fprintf(stderr, " sc-reader-name Smartcard reader name to use\n"); fprintf(stderr, " sc-card-name Specifies the card name of the smartcard to use\n"); #endif fprintf(stderr, "\n"); } static int handle_disconnect_reason(RD_BOOL deactivated, uint16 reason) { char *text; int retval; switch (reason) { case exDiscReasonNoInfo: text = "No information available"; if (deactivated) retval = EX_OK; else retval = EXRD_UNKNOWN; break; case exDiscReasonAPIInitiatedDisconnect: text = "Server initiated disconnect"; retval = EXRD_API_DISCONNECT; break; case exDiscReasonAPIInitiatedLogoff: text = "Server initiated logoff"; retval = EXRD_API_LOGOFF; break; case exDiscReasonServerIdleTimeout: text = "Server idle timeout reached"; retval = EXRD_IDLE_TIMEOUT; break; case exDiscReasonServerLogonTimeout: text = "Server logon timeout reached"; retval = EXRD_LOGON_TIMEOUT; break; case exDiscReasonReplacedByOtherConnection: text = "The session was replaced"; retval = EXRD_REPLACED; break; case exDiscReasonOutOfMemory: text = "The server is out of memory"; retval = EXRD_OUT_OF_MEM; break; case exDiscReasonServerDeniedConnection: text = "The server denied the connection"; retval = EXRD_DENIED; break; case exDiscReasonServerDeniedConnectionFips: text = "The server denied the connection for security reason"; retval = EXRD_DENIED_FIPS; break; case exDiscReasonServerInsufficientPrivileges: text = "The user cannot connect to the server due to insufficient access privileges."; retval = EXRD_INSUFFICIENT_PRIVILEGES; break; case exDiscReasonServerFreshCredentialsRequired: text = "The server does not accept saved user credentials and requires that the user enter their credentials for each connection."; retval = EXRD_FRESH_CREDENTIALS_REQUIRED; break; case exDiscReasonRPCInitiatedDisconnectByUser: text = "Disconnect initiated by administration tool"; retval = EXRD_RPC_DISCONNECT_BY_USER; break; case exDiscReasonByUser: text = "Disconnect initiated by user"; retval = EXRD_DISCONNECT_BY_USER; break; case exDiscReasonLicenseInternal: text = "Internal licensing error"; retval = EXRD_LIC_INTERNAL; break; case exDiscReasonLicenseNoLicenseServer: text = "No license server available"; retval = EXRD_LIC_NOSERVER; break; case exDiscReasonLicenseNoLicense: text = "No valid license available"; retval = EXRD_LIC_NOLICENSE; break; case exDiscReasonLicenseErrClientMsg: text = "Invalid licensing message"; retval = EXRD_LIC_MSG; break; case exDiscReasonLicenseHwidDoesntMatchLicense: text = "Hardware id doesn't match software license"; retval = EXRD_LIC_HWID; break; case exDiscReasonLicenseErrClientLicense: text = "Client license error"; retval = EXRD_LIC_CLIENT; break; case exDiscReasonLicenseCantFinishProtocol: text = "Network error during licensing protocol"; retval = EXRD_LIC_NET; break; case exDiscReasonLicenseClientEndedProtocol: text = "Licensing protocol was not completed"; retval = EXRD_LIC_PROTO; break; case exDiscReasonLicenseErrClientEncryption: text = "Incorrect client license encryption"; retval = EXRD_LIC_ENC; break; case exDiscReasonLicenseCantUpgradeLicense: text = "Can't upgrade license"; retval = EXRD_LIC_UPGRADE; break; case exDiscReasonLicenseNoRemoteConnections: text = "The server is not licensed to accept remote connections"; retval = EXRD_LIC_NOREMOTE; break; default: if (reason > 0x1000 && reason < 0x7fff) { text = "Internal protocol error"; } else { text = "Unknown reason"; } retval = EXRD_UNKNOWN; } if (reason != exDiscReasonNoInfo) fprintf(stderr, "disconnect: %s.\n", text); return retval; } static void rdesktop_reset_state(void) { rdp_reset_state(); #ifdef WITH_SCARD scard_reset_state(); #endif #ifdef WITH_RDPSND rdpsnd_reset_state(); #endif } static RD_BOOL read_password(char *password, int size) { struct termios tios; RD_BOOL ret = False; int istty = 0; char *p; if (tcgetattr(STDIN_FILENO, &tios) == 0) { fprintf(stderr, "Password: "); tios.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &tios); istty = 1; } if (fgets(password, size, stdin) != NULL) { ret = True; /* strip final newline */ p = strchr(password, '\n'); if (p != NULL) *p = 0; } if (istty) { tios.c_lflag |= ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &tios); fprintf(stderr, "\n"); } return ret; } static void parse_server_and_port(char *server) { char *p; #ifdef IPv6 int addr_colons; #endif #ifdef IPv6 p = server; addr_colons = 0; while (*p) if (*p++ == ':') addr_colons++; if (addr_colons >= 2) { /* numeric IPv6 style address format - [1:2:3::4]:port */ p = strchr(server, ']'); if (*server == '[' && p != NULL) { if (*(p + 1) == ':' && *(p + 2) != '\0') g_tcp_port_rdp = strtol(p + 2, NULL, 10); /* remove the port number and brackets from the address */ *p = '\0'; strncpy(server, server + 1, strlen(server)); } } else { /* dns name or IPv4 style address format - server.example.com:port or 1.2.3.4:port */ p = strchr(server, ':'); if (p != NULL) { g_tcp_port_rdp = strtol(p + 1, NULL, 10); *p = 0; } } #else /* no IPv6 support */ p = strchr(server, ':'); if (p != NULL) { g_tcp_port_rdp = strtol(p + 1, NULL, 10); *p = 0; } #endif /* IPv6 */ } /* Client program */ int main(int argc, char *argv[]) { char server[256]; char fullhostname[64]; char domain[256]; char shell[256]; char directory[256]; RD_BOOL prompt_password, deactivated; struct passwd *pw; uint32 flags, ext_disc_reason = 0; char *p; int c; char *locale = NULL; int username_option = 0; RD_BOOL geometry_option = False; #ifdef WITH_RDPSND char *rdpsnd_optarg = NULL; #endif #ifdef HAVE_LOCALE_H /* Set locale according to environment */ locale = setlocale(LC_ALL, ""); if (locale) { locale = xstrdup(locale); } #endif /* Ignore SIGPIPE, since we are using popen() */ struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGPIPE, &act, NULL); /* setup default flags for TS_INFO_PACKET */ flags = RDP_INFO_MOUSE | RDP_INFO_DISABLECTRLALTDEL | RDP_INFO_UNICODE | RDP_INFO_MAXIMIZESHELL | RDP_INFO_ENABLEWINDOWSKEY; prompt_password = False; g_seamless_spawn_cmd[0] = domain[0] = g_password[0] = shell[0] = directory[0] = 0; g_embed_wnd = 0; g_num_devices = 0; #ifdef RDP2VNC #define VNCOPT "V:Q:" #else #define VNCOPT #endif while ((c = getopt(argc, argv, VNCOPT "A:u:L:d:s:c:p:n:k:g:o:fbBeEitmzCDKS:T:NX:a:x:Pr:045h?")) != -1) { switch (c) { #ifdef RDP2VNC case 'V': rfb_port = strtol(optarg, NULL, 10); if (rfb_port < 100) rfb_port += 5900; break; case 'Q': defer_time = strtol(optarg, NULL, 10); if (defer_time < 0) defer_time = 0; break; #endif case 'A': g_seamless_rdp = True; STRNCPY(g_seamless_shell, optarg, sizeof(g_seamless_shell)); break; case 'u': g_username = (char *) xmalloc(strlen(optarg) + 1); STRNCPY(g_username, optarg, strlen(optarg) + 1); username_option = 1; break; case 'L': #ifdef HAVE_ICONV STRNCPY(g_codepage, optarg, sizeof(g_codepage)); #else error("iconv support not available\n"); #endif break; case 'd': STRNCPY(domain, optarg, sizeof(domain)); break; case 's': STRNCPY(shell, optarg, sizeof(shell)); g_seamless_persistent_mode = False; break; case 'c': STRNCPY(directory, optarg, sizeof(directory)); break; case 'p': if ((optarg[0] == '-') && (optarg[1] == 0)) { prompt_password = True; break; } STRNCPY(g_password, optarg, sizeof(g_password)); flags |= RDP_INFO_AUTOLOGON; /* try to overwrite argument so it won't appear in ps */ p = optarg; while (*p) *(p++) = 'X'; break; #ifdef WITH_SCARD case 'i': flags |= RDP_INFO_PASSWORD_IS_SC_PIN; g_use_password_as_pin = True; break; #endif case 't': g_use_ctrl = False; break; case 'n': STRNCPY(g_hostname, optarg, sizeof(g_hostname)); break; case 'k': STRNCPY(g_keymapname, optarg, sizeof(g_keymapname)); break; case 'g': geometry_option = True; g_fullscreen = False; if (!strcmp(optarg, "workarea")) { g_sizeopt = 1; break; } g_width = strtol(optarg, &p, 10); if (g_width <= 0) { error("invalid geometry\n"); return EX_USAGE; } if (*p == 'x') g_height = strtol(p + 1, &p, 10); if (g_height <= 0) { error("invalid geometry\n"); return EX_USAGE; } if (*p == '%') { g_sizeopt = -g_width; g_width = 800; p++; } if (*p == '+' || *p == '-') { g_pos |= (*p == '-') ? 2 : 1; g_xpos = strtol(p, &p, 10); } if (*p == '+' || *p == '-') { g_pos |= (*p == '-') ? 4 : 1; g_ypos = strtol(p, NULL, 10); } break; case 'f': g_fullscreen = True; break; case 'b': g_bitmap_cache = False; break; case 'B': g_ownbackstore = False; break; case 'e': g_encryption_initial = g_encryption = False; break; case 'E': g_packet_encryption = False; break; case 'm': g_sendmotion = False; break; case 'C': g_owncolmap = True; break; case 'D': g_hide_decorations = True; break; case 'K': g_grab_keyboard = False; break; case 'S': if (!strcmp(optarg, "standard")) { g_win_button_size = 18; break; } g_win_button_size = strtol(optarg, &p, 10); if (*p) { error("invalid button size\n"); return EX_USAGE; } break; case 'T': STRNCPY(g_title, optarg, sizeof(g_title)); break; case 'N': g_numlock_sync = True; break; case 'X': g_embed_wnd = strtol(optarg, NULL, 0); break; case 'a': g_server_depth = strtol(optarg, NULL, 10); if (g_server_depth != 8 && g_server_depth != 16 && g_server_depth != 15 && g_server_depth != 24 && g_server_depth != 32) { error("Invalid server colour depth.\n"); return EX_USAGE; } break; case 'z': DEBUG(("rdp compression enabled\n")); flags |= (RDP_INFO_COMPRESSION | RDP_INFO_COMPRESSION2); break; case 'x': if (str_startswith(optarg, "m")) /* modem */ { g_rdp5_performanceflags = RDP5_NO_CURSOR_SHADOW | RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS | RDP5_NO_THEMING; } else if (str_startswith(optarg, "b")) /* broadband */ { g_rdp5_performanceflags = RDP5_NO_CURSOR_SHADOW | RDP5_NO_WALLPAPER; } else if (str_startswith(optarg, "l")) /* lan */ { g_rdp5_performanceflags = RDP5_NO_CURSOR_SHADOW | RDP5_DISABLE_NOTHING; } else { g_rdp5_performanceflags = RDP5_NO_CURSOR_SHADOW | strtol(optarg, NULL, 16); } break; case 'P': g_bitmap_cache_persist_enable = True; break; case 'r': if (str_startswith(optarg, "sound")) { optarg += 5; if (*optarg == ':') { optarg++; while ((p = next_arg(optarg, ','))) { if (str_startswith(optarg, "remote")) flags |= RDP_INFO_REMOTE_CONSOLE_AUDIO; if (str_startswith(optarg, "local")) #ifdef WITH_RDPSND { rdpsnd_optarg = next_arg(optarg, ':'); g_rdpsnd = True; } #else warning("Not compiled with sound support\n"); #endif if (str_startswith(optarg, "off")) #ifdef WITH_RDPSND g_rdpsnd = False; #else warning("Not compiled with sound support\n"); #endif optarg = p; } } else { #ifdef WITH_RDPSND g_rdpsnd = True; #else warning("Not compiled with sound support\n"); #endif } } else if (str_startswith(optarg, "disk")) { /* -r disk:h:=/mnt/floppy */ disk_enum_devices(&g_num_devices, optarg + 4); } else if (str_startswith(optarg, "comport")) { serial_enum_devices(&g_num_devices, optarg + 7); } else if (str_startswith(optarg, "lspci")) { g_lspci_enabled = True; } else if (str_startswith(optarg, "lptport")) { parallel_enum_devices(&g_num_devices, optarg + 7); } else if (str_startswith(optarg, "printer")) { printer_enum_devices(&g_num_devices, optarg + 7); } else if (str_startswith(optarg, "clientname")) { g_rdpdr_clientname = xmalloc(strlen(optarg + 11) + 1); strcpy(g_rdpdr_clientname, optarg + 11); } else if (str_startswith(optarg, "clipboard")) { optarg += 9; if (*optarg == ':') { optarg++; if (str_startswith(optarg, "off")) g_rdpclip = False; else cliprdr_set_mode(optarg); } else g_rdpclip = True; } else if (strncmp("scard", optarg, 5) == 0) { #ifdef WITH_SCARD scard_enum_devices(&g_num_devices, optarg + 5); #else warning("Not compiled with smartcard support\n"); #endif } else { warning("Unknown -r argument\n\n\tPossible arguments are: comport, disk, lptport, printer, sound, clipboard, scard\n"); } break; case '0': g_console_session = True; break; case '4': g_rdp_version = RDP_V4; break; case '5': g_rdp_version = RDP_V5; break; #if WITH_SCARD case 'o': { char *p = strchr(optarg, '='); if (p == NULL) { warning("Skipping option '%s' specified, lacks name=value format.\n"); continue; } if (strncmp(optarg, "sc-csp-name", strlen("sc-scp-name")) == 0) g_sc_csp_name = strdup(p + 1); else if (strncmp (optarg, "sc-reader-name", strlen("sc-reader-name")) == 0) g_sc_reader_name = strdup(p + 1); else if (strncmp (optarg, "sc-card-name", strlen("sc-card-name")) == 0) g_sc_card_name = strdup(p + 1); else if (strncmp (optarg, "sc-container-name", strlen("sc-container-name")) == 0) g_sc_container_name = strdup(p + 1); } break; #endif case 'h': case '?': default: usage(argv[0]); return EX_USAGE; } } if (argc - optind != 1) { usage(argv[0]); return EX_USAGE; } STRNCPY(server, argv[optind], sizeof(server)); parse_server_and_port(server); if (g_seamless_rdp) { if (shell[0]) STRNCPY(g_seamless_spawn_cmd, shell, sizeof(g_seamless_spawn_cmd)); STRNCPY(shell, g_seamless_shell, sizeof(shell)); if (g_win_button_size) { error("You cannot use -S and -A at the same time\n"); return EX_USAGE; } g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG; if (geometry_option) { error("You cannot use -g and -A at the same time\n"); return EX_USAGE; } if (g_fullscreen) { error("You cannot use -f and -A at the same time\n"); return EX_USAGE; } if (g_hide_decorations) { error("You cannot use -D and -A at the same time\n"); return EX_USAGE; } if (g_embed_wnd) { error("You cannot use -X and -A at the same time\n"); return EX_USAGE; } if (g_rdp_version < RDP_V5) { error("You cannot use -4 and -A at the same time\n"); return EX_USAGE; } g_sizeopt = -100; g_grab_keyboard = False; } if (!username_option) { pw = getpwuid(getuid()); if ((pw == NULL) || (pw->pw_name == NULL)) { error("could not determine username, use -u\n"); return EX_OSERR; } /* +1 for trailing \0 */ int pwlen = strlen(pw->pw_name) + 1; g_username = (char *) xmalloc(pwlen); STRNCPY(g_username, pw->pw_name, pwlen); } #ifdef HAVE_ICONV if (g_codepage[0] == 0) { if (setlocale(LC_CTYPE, "")) { STRNCPY(g_codepage, nl_langinfo(CODESET), sizeof(g_codepage)); } else { STRNCPY(g_codepage, DEFAULT_CODEPAGE, sizeof(g_codepage)); } } #endif if (g_hostname[0] == 0) { if (gethostname(fullhostname, sizeof(fullhostname)) == -1) { error("could not determine local hostname, use -n\n"); return EX_OSERR; } p = strchr(fullhostname, '.'); if (p != NULL) *p = 0; STRNCPY(g_hostname, fullhostname, sizeof(g_hostname)); } if (g_keymapname[0] == 0) { if (locale && xkeymap_from_locale(locale)) { fprintf(stderr, "Autoselected keyboard map %s\n", g_keymapname); } else { STRNCPY(g_keymapname, "en-us", sizeof(g_keymapname)); } } if (locale) xfree(locale); if (prompt_password && read_password(g_password, sizeof(g_password))) flags |= RDP_INFO_AUTOLOGON; if (g_title[0] == 0) { strcpy(g_title, "rdesktop - "); strncat(g_title, server, sizeof(g_title) - sizeof("rdesktop - ")); } #ifdef RDP2VNC rdp2vnc_connect(server, flags, domain, g_password, shell, directory); return EX_OK; #else /* Only startup ctrl functionality is seamless are used for now. */ if (g_use_ctrl && g_seamless_rdp) { if (ctrl_init(server, domain, g_username) < 0) { error("Failed to initialize ctrl mode."); exit(1); } if (ctrl_is_slave()) { fprintf(stdout, "rdesktop in slave mode sending command to master process.\n"); if (g_seamless_spawn_cmd[0]) return ctrl_send_command("seamless.spawn", g_seamless_spawn_cmd); fprintf(stdout, "No command specified to be spawn in seamless mode.\n"); return EX_USAGE; } } if (!ui_init()) return EX_OSERR; #ifdef WITH_RDPSND if (!rdpsnd_init(rdpsnd_optarg)) warning("Initializing sound-support failed!\n"); #endif if (g_lspci_enabled) lspci_init(); rdpdr_init(); g_reconnect_loop = False; while (1) { rdesktop_reset_state(); if (g_redirect) { STRNCPY(domain, g_redirect_domain, sizeof(domain)); xfree(g_username); g_username = (char *) xmalloc(strlen(g_redirect_username) + 1); STRNCPY(g_username, g_redirect_username, strlen(g_redirect_username) + 1); STRNCPY(server, g_redirect_server, sizeof(server)); flags |= RDP_INFO_AUTOLOGON; fprintf(stderr, "Redirected to %s@%s session %d.\n", g_redirect_username, g_redirect_server, g_redirect_session_id); /* A redirect on SSL from a 2003 WTS will result in a 'connection reset by peer' and therefor we just clear this error before we connect to redirected server. */ g_network_error = False; g_redirect = False; } ui_init_connection(); if (!rdp_connect (server, flags, domain, g_password, shell, directory, g_reconnect_loop)) { g_network_error = False; if (g_reconnect_loop == False) return EX_PROTOCOL; /* check if auto reconnect cookie has timed out */ if (time(NULL) - g_reconnect_random_ts > RECONNECT_TIMEOUT) { fprintf(stderr, "Tried to reconnect for %d minutes, giving up.\n", RECONNECT_TIMEOUT / 60); return EX_PROTOCOL; } sleep(4); continue; } if (g_redirect) { rdp_disconnect(); continue; } /* By setting encryption to False here, we have an encrypted login packet but unencrypted transfer of other packets */ if (!g_packet_encryption) g_encryption_initial = g_encryption = False; DEBUG(("Connection successful.\n")); rd_create_ui(); tcp_run_ui(True); deactivated = False; g_reconnect_loop = False; rdp_main_loop(&deactivated, &ext_disc_reason); tcp_run_ui(False); DEBUG(("Disconnecting...\n")); rdp_disconnect(); if (g_redirect) continue; /* handle network error and start autoreconnect */ if (g_network_error && !deactivated) { fprintf(stderr, "Disconnected due to network error, retrying to reconnect for %d minutes.\n", RECONNECT_TIMEOUT / 60); g_network_error = False; g_reconnect_loop = True; continue; } ui_seamless_end(); ui_destroy_window(); /* Enter a reconnect loop if we have a pending resize request */ if (g_pending_resize) { g_pending_resize = False; g_reconnect_loop = True; continue; } break; } cache_save_state(); ui_deinit(); if (g_user_quit) return EXRD_WINDOW_CLOSED; return handle_disconnect_reason(deactivated, ext_disc_reason); #endif if (g_redirect_username) xfree(g_redirect_username); xfree(g_username); } #ifdef EGD_SOCKET /* Read 32 random bytes from PRNGD or EGD socket (based on OpenSSL RAND_egd) */ static RD_BOOL generate_random_egd(uint8 * buf) { struct sockaddr_un addr; RD_BOOL ret = False; int fd; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) return False; addr.sun_family = AF_UNIX; memcpy(addr.sun_path, EGD_SOCKET, sizeof(EGD_SOCKET)); if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) goto err; /* PRNGD and EGD use a simple communications protocol */ buf[0] = 1; /* Non-blocking (similar to /dev/urandom) */ buf[1] = 32; /* Number of requested random bytes */ if (write(fd, buf, 2) != 2) goto err; if ((read(fd, buf, 1) != 1) || (buf[0] == 0)) /* Available? */ goto err; if (read(fd, buf, 32) != 32) goto err; ret = True; err: close(fd); return ret; } #endif /* Generate a 32-byte random for the secure transport code. */ void generate_random(uint8 * random) { struct stat st; struct tms tmsbuf; RDSSL_MD5 md5; uint32 *r; int fd, n; /* If we have a kernel random device, try that first */ if (((fd = open("/dev/urandom", O_RDONLY)) != -1) || ((fd = open("/dev/random", O_RDONLY)) != -1)) { n = read(fd, random, 32); close(fd); if (n == 32) return; } #ifdef EGD_SOCKET /* As a second preference use an EGD */ if (generate_random_egd(random)) return; #endif /* Otherwise use whatever entropy we can gather - ideas welcome. */ r = (uint32 *) random; r[0] = (getpid()) | (getppid() << 16); r[1] = (getuid()) | (getgid() << 16); r[2] = times(&tmsbuf); /* system uptime (clocks) */ gettimeofday((struct timeval *) &r[3], NULL); /* sec and usec */ stat("/tmp", &st); r[5] = st.st_atime; r[6] = st.st_mtime; r[7] = st.st_ctime; /* Hash both halves with MD5 to obscure possible patterns */ rdssl_md5_init(&md5); rdssl_md5_update(&md5, random, 16); rdssl_md5_final(&md5, random); rdssl_md5_update(&md5, random + 16, 16); rdssl_md5_final(&md5, random + 16); } /* malloc; exit if out of memory */ void * xmalloc(int size) { void *mem = malloc(size); if (mem == NULL) { error("xmalloc %d\n", size); exit(EX_UNAVAILABLE); } return mem; } /* Exit on NULL pointer. Use to verify result from XGetImage etc */ void exit_if_null(void *ptr) { if (ptr == NULL) { error("unexpected null pointer. Out of memory?\n"); exit(EX_UNAVAILABLE); } } /* strdup */ char * xstrdup(const char *s) { char *mem = strdup(s); if (mem == NULL) { perror("strdup"); exit(EX_UNAVAILABLE); } return mem; } /* realloc; exit if out of memory */ void * xrealloc(void *oldmem, size_t size) { void *mem; if (size == 0) size = 1; mem = realloc(oldmem, size); if (mem == NULL) { error("xrealloc %ld\n", size); exit(EX_UNAVAILABLE); } return mem; } /* free */ void xfree(void *mem) { free(mem); } /* report an error */ void error(char *format, ...) { va_list ap; fprintf(stderr, "ERROR: "); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } /* report a warning */ void warning(char *format, ...) { va_list ap; fprintf(stderr, "WARNING: "); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } /* report an unimplemented protocol feature */ void unimpl(char *format, ...) { va_list ap; fprintf(stderr, "NOT IMPLEMENTED: "); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } /* produce a hex dump */ void hexdump(unsigned char *p, unsigned int len) { unsigned char *line = p; int i, thisline, offset = 0; while (offset < len) { printf("%04x ", offset); thisline = len - offset; if (thisline > 16) thisline = 16; for (i = 0; i < thisline; i++) printf("%02x ", line[i]); for (; i < 16; i++) printf(" "); for (i = 0; i < thisline; i++) printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); printf("\n"); offset += thisline; line += thisline; } } /* input: src is the string we look in for needle. Needle may be escaped by a backslash, in that case we ignore that particular needle. return value: returns next src pointer, for succesive executions, like in a while loop if retval is 0, then there are no more args. pitfalls: src is modified. 0x00 chars are inserted to terminate strings. return val, points on the next val chr after ins 0x00 example usage: while( (pos = next_arg( optarg, ',')) ){ printf("%s\n",optarg); optarg=pos; } */ char * next_arg(char *src, char needle) { char *nextval; char *p; char *mvp = 0; /* EOS */ if (*src == (char) 0x00) return 0; p = src; /* skip escaped needles */ while ((nextval = strchr(p, needle))) { mvp = nextval - 1; /* found backslashed needle */ if (*mvp == '\\' && (mvp > src)) { /* move string one to the left */ while (*(mvp + 1) != (char) 0x00) { *mvp = *(mvp + 1); mvp++; } *mvp = (char) 0x00; p = nextval; } else { p = nextval + 1; break; } } /* more args available */ if (nextval) { *nextval = (char) 0x00; return ++nextval; } /* no more args after this, jump to EOS */ nextval = src + strlen(src); return nextval; } void toupper_str(char *p) { while (*p) { if ((*p >= 'a') && (*p <= 'z')) *p = toupper((int) *p); p++; } } RD_BOOL str_startswith(const char *s, const char *prefix) { return (strncmp(s, prefix, strlen(prefix)) == 0); } /* Split input into lines, and call linehandler for each line. Incomplete lines are saved in the rest variable, which should initially point to NULL. When linehandler returns False, stop and return False. Otherwise, return True. */ RD_BOOL str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data) { char *buf, *p; char *oldrest; size_t inputlen; size_t buflen; size_t restlen = 0; RD_BOOL ret = True; /* Copy data to buffer */ inputlen = strlen(input); if (*rest) restlen = strlen(*rest); buflen = restlen + inputlen + 1; buf = (char *) xmalloc(buflen); buf[0] = '\0'; if (*rest) STRNCPY(buf, *rest, buflen); strncat(buf, input, inputlen); p = buf; while (1) { char *newline = strchr(p, '\n'); if (newline) { *newline = '\0'; if (!linehandler(p, data)) { p = newline + 1; ret = False; break; } p = newline + 1; } else { break; } } /* Save in rest */ oldrest = *rest; restlen = buf + buflen - p; *rest = (char *) xmalloc(restlen); STRNCPY((*rest), p, restlen); xfree(oldrest); xfree(buf); return ret; } /* Execute the program specified by argv. For each line in stdout/stderr output, call linehandler. Returns false on failure. */ RD_BOOL subprocess(char *const argv[], str_handle_lines_t linehandler, void *data) { pid_t child; int fd[2]; int n = 1; char output[256]; char *rest = NULL; if (pipe(fd) < 0) { perror("pipe"); return False; } if ((child = fork()) < 0) { perror("fork"); return False; } /* Child */ if (child == 0) { /* Close read end */ close(fd[0]); /* Redirect stdout and stderr to pipe */ dup2(fd[1], 1); dup2(fd[1], 2); /* Execute */ execvp(argv[0], argv); perror("Error executing child"); _exit(128); } /* Parent. Close write end. */ close(fd[1]); while (n > 0) { n = read(fd[0], output, 255); output[n] = '\0'; str_handle_lines(output, &rest, linehandler, data); } xfree(rest); return True; } /* not all clibs got ltoa */ #define LTOA_BUFSIZE (sizeof(long) * 8 + 1) char * l_to_a(long N, int base) { static char ret[LTOA_BUFSIZE]; char *head = ret, buf[LTOA_BUFSIZE], *tail = buf + sizeof(buf); register int divrem; if (base < 36 || 2 > base) base = 10; if (N < 0) { *head++ = '-'; N = -N; } tail = buf + sizeof(buf); *--tail = 0; do { divrem = N % base; *--tail = (divrem <= 9) ? divrem + '0' : divrem + 'a' - 10; N /= base; } while (N); strcpy(head, tail); return ret; } int load_licence(unsigned char **data) { uint8 ho[20], hi[16]; char *home, path[PATH_MAX], hash[41]; struct stat st; int fd, length; home = getenv("HOME"); if (home == NULL) return -1; memset(hi, 0, sizeof(hi)); snprintf((char *) hi, 16, "%s", g_hostname); sec_hash_sha1_16(ho, hi, g_static_rdesktop_salt_16); sec_hash_to_string(hash, sizeof(hash), ho, sizeof(ho)); snprintf(path, PATH_MAX, "%s" RDESKTOP_LICENSE_STORE "/%s.cal", home, hash); path[sizeof(path) - 1] = '\0'; fd = open(path, O_RDONLY); if (fd == -1) { /* fallback to try reading old license file */ snprintf(path, PATH_MAX, "%s/.rdesktop/license.%s", home, g_hostname); path[sizeof(path) - 1] = '\0'; if ((fd = open(path, O_RDONLY)) == -1) return -1; } if (fstat(fd, &st)) { close(fd); return -1; } *data = (uint8 *) xmalloc(st.st_size); length = read(fd, *data, st.st_size); close(fd); return length; } void save_licence(unsigned char *data, int length) { uint8 ho[20], hi[16]; char *home, path[PATH_MAX], tmppath[PATH_MAX], hash[41]; int fd; home = getenv("HOME"); if (home == NULL) return; snprintf(path, PATH_MAX, "%s" RDESKTOP_LICENSE_STORE, home); path[sizeof(path) - 1] = '\0'; if (utils_mkdir_p(path, 0700) == -1) { perror(path); return; } memset(hi, 0, sizeof(hi)); snprintf((char *) hi, 16, "%s", g_hostname); sec_hash_sha1_16(ho, hi, g_static_rdesktop_salt_16); sec_hash_to_string(hash, sizeof(hash), ho, sizeof(ho)); /* write licence to {sha1}.cal.new, then atomically rename to {sha1}.cal */ snprintf(path, PATH_MAX, "%s" RDESKTOP_LICENSE_STORE "/%s.cal", home, hash); path[sizeof(path) - 1] = '\0'; snprintf(tmppath, PATH_MAX, "%s.new", path); path[sizeof(path) - 1] = '\0'; fd = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd == -1) { perror(tmppath); return; } if (write(fd, data, length) != length) { perror(tmppath); unlink(tmppath); } else if (rename(tmppath, path) == -1) { perror(path); unlink(tmppath); } close(fd); } /* create rdesktop ui */ void rd_create_ui() { /* only create a window if we dont have one intialized */ if (!ui_have_window()) { if (!ui_create_window()) exit(EX_OSERR); } } /* Create the bitmap cache directory */ RD_BOOL rd_pstcache_mkdir(void) { char *home; char bmpcache_dir[256]; home = getenv("HOME"); if (home == NULL) return False; sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop"); if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST) { perror(bmpcache_dir); return False; } sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache"); if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST) { perror(bmpcache_dir); return False; } return True; } /* open a file in the .rdesktop directory */ int rd_open_file(char *filename) { char *home; char fn[256]; int fd; home = getenv("HOME"); if (home == NULL) return -1; sprintf(fn, "%s/.rdesktop/%s", home, filename); fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) perror(fn); return fd; } /* close file */ void rd_close_file(int fd) { close(fd); } /* read from file*/ int rd_read_file(int fd, void *ptr, int len) { return read(fd, ptr, len); } /* write to file */ int rd_write_file(int fd, void *ptr, int len) { return write(fd, ptr, len); } /* move file pointer */ int rd_lseek_file(int fd, int offset) { return lseek(fd, offset, SEEK_SET); } /* do a write lock on a file */ RD_BOOL rd_lock_file(int fd, int start, int len) { struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = start; lock.l_len = len; if (fcntl(fd, F_SETLK, &lock) == -1) return False; return True; } rdesktop-1.8.3/rdp5.c0000664000770100510440000000563311640565273013333 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP5 short form PDU processing Copyright (C) Matthew Chapman 1999-2008 Copyright 2003-2008 Erik Forsberg for Cendio AB 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 3 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, see . */ #include "rdesktop.h" extern uint8 *g_next_packet; extern RDPCOMP g_mppc_dict; void rdp5_process(STREAM s) { uint16 length, count, x, y; uint8 type, ctype; uint8 *next; uint32 roff, rlen; struct stream *ns = &(g_mppc_dict.ns); struct stream *ts; #if 0 printf("RDP5 data:\n"); hexdump(s->p, s->end - s->p); #endif ui_begin_update(); while (s->p < s->end) { in_uint8(s, type); if (type & RDP5_COMPRESSED) { in_uint8(s, ctype); in_uint16_le(s, length); type ^= RDP5_COMPRESSED; } else { ctype = 0; in_uint16_le(s, length); } g_next_packet = next = s->p + length; if (ctype & RDP_MPPC_COMPRESSED) { if (mppc_expand(s->p, length, ctype, &roff, &rlen) == -1) error("error while decompressing packet\n"); /* allocate memory and copy the uncompressed data into the temporary stream */ ns->data = (uint8 *) xrealloc(ns->data, rlen); memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen); ns->size = rlen; ns->end = (ns->data + ns->size); ns->p = ns->data; ns->rdp_hdr = ns->p; ts = ns; } else ts = s; switch (type) { case 0: /* update orders */ in_uint16_le(ts, count); process_orders(ts, count); break; case 1: /* update bitmap */ in_uint8s(ts, 2); /* part length */ process_bitmap_updates(ts); break; case 2: /* update palette */ in_uint8s(ts, 2); /* uint16 = 2 */ process_palette(ts); break; case 3: /* update synchronize */ break; case 5: /* null pointer */ ui_set_null_cursor(); break; case 6: /* default pointer */ break; case 8: /* pointer position */ in_uint16_le(ts, x); in_uint16_le(ts, y); if (s_check(ts)) ui_move_pointer(x, y); break; case 9: /* color pointer */ process_colour_pointer_pdu(ts); break; case 10: /* cached pointer */ process_cached_pointer_pdu(ts); break; case 11: process_new_pointer_pdu(ts); break; default: unimpl("RDP5 opcode %d\n", type); } s->p = next; } ui_end_update(); } rdesktop-1.8.3/rdp.c0000664000770100510440000012227012377346357013253 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP layer Copyright (C) Matthew Chapman 1999-2008 Copyright 2003-2011 Peter Astrand for Cendio AB Copyright 2011-2014 Henrik Andersson for Cendio AB 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 3 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, see . */ #include #ifndef _WIN32 #include #include #endif #include "rdesktop.h" #include "ssl.h" #ifdef HAVE_ICONV #ifdef HAVE_ICONV_H #include #endif #ifndef ICONV_CONST #define ICONV_CONST "" #endif #endif extern uint16 g_mcs_userid; extern char *g_username; extern char g_password[64]; extern char g_codepage[16]; extern RD_BOOL g_bitmap_compression; extern RD_BOOL g_orders; extern RD_BOOL g_encryption; extern RD_BOOL g_desktop_save; extern RD_BOOL g_polygon_ellipse_orders; extern RDP_VERSION g_rdp_version; extern uint16 g_server_rdp_version; extern uint32 g_rdp5_performanceflags; extern int g_server_depth; extern int g_width; extern int g_height; extern RD_BOOL g_bitmap_cache; extern RD_BOOL g_bitmap_cache_persist_enable; extern RD_BOOL g_numlock_sync; extern RD_BOOL g_pending_resize; extern RD_BOOL g_network_error; uint8 *g_next_packet; uint32 g_rdp_shareid; extern RDPCOMP g_mppc_dict; /* Session Directory support */ extern RD_BOOL g_redirect; extern char *g_redirect_server; extern uint32 g_redirect_server_len; extern char *g_redirect_domain; extern uint32 g_redirect_domain_len; extern char *g_redirect_username; extern uint32 g_redirect_username_len; extern uint8 *g_redirect_lb_info; extern uint32 g_redirect_lb_info_len; extern uint8 *g_redirect_cookie; extern uint32 g_redirect_cookie_len; extern uint32 g_redirect_flags; extern uint32 g_redirect_session_id; /* END Session Directory support */ extern uint32 g_reconnect_logonid; extern char g_reconnect_random[16]; extern time_t g_reconnect_random_ts; extern RD_BOOL g_has_reconnect_random; extern uint8 g_client_random[SEC_RANDOM_SIZE]; #if WITH_DEBUG static uint32 g_packetno; #endif #ifdef HAVE_ICONV static RD_BOOL g_iconv_works = True; #endif /* Receive an RDP packet */ static STREAM rdp_recv(uint8 * type) { static STREAM rdp_s; uint16 length, pdu_type; uint8 rdpver; if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL)) { rdp_s = sec_recv(&rdpver); if (rdp_s == NULL) return NULL; if (rdpver == 0xff) { g_next_packet = rdp_s->end; *type = 0; return rdp_s; } else if (rdpver != 3) { /* rdp5_process should move g_next_packet ok */ rdp5_process(rdp_s); *type = 0; return rdp_s; } g_next_packet = rdp_s->p; } else { rdp_s->p = g_next_packet; } in_uint16_le(rdp_s, length); /* 32k packets are really 8, keepalive fix */ if (length == 0x8000) { g_next_packet += 8; *type = 0; return rdp_s; } in_uint16_le(rdp_s, pdu_type); in_uint8s(rdp_s, 2); /* userid */ *type = pdu_type & 0xf; #if WITH_DEBUG DEBUG(("RDP packet #%d, (type %x)\n", ++g_packetno, *type)); hexdump(g_next_packet, length); #endif /* */ g_next_packet += length; return rdp_s; } /* Initialise an RDP data packet */ static STREAM rdp_init_data(int maxlen) { STREAM s; s = sec_init(g_encryption ? SEC_ENCRYPT : 0, maxlen + 18); s_push_layer(s, rdp_hdr, 18); return s; } /* Send an RDP data packet */ static void rdp_send_data(STREAM s, uint8 data_pdu_type) { uint16 length; s_pop_layer(s, rdp_hdr); length = s->end - s->p; out_uint16_le(s, length); out_uint16_le(s, (RDP_PDU_DATA | 0x10)); out_uint16_le(s, (g_mcs_userid + 1001)); out_uint32_le(s, g_rdp_shareid); out_uint8(s, 0); /* pad */ out_uint8(s, 1); /* streamid */ out_uint16_le(s, (length - 14)); out_uint8(s, data_pdu_type); out_uint8(s, 0); /* compress_type */ out_uint16(s, 0); /* compress_len */ sec_send(s, g_encryption ? SEC_ENCRYPT : 0); } /* Output a string in Unicode */ void rdp_out_unistr(STREAM s, char *string, int len) { if (string == NULL || len == 0) return; #ifdef HAVE_ICONV size_t ibl = strlen(string), obl = len + 2; static iconv_t iconv_h = (iconv_t) - 1; char *pin = string, *pout = (char *) s->p; memset(pout, 0, len + 4); if (g_iconv_works) { if (iconv_h == (iconv_t) - 1) { size_t i = 1, o = 4; if ((iconv_h = iconv_open(WINDOWS_CODEPAGE, g_codepage)) == (iconv_t) - 1) { warning("rdp_out_unistr: iconv_open[%s -> %s] fail %p\n", g_codepage, WINDOWS_CODEPAGE, iconv_h); g_iconv_works = False; rdp_out_unistr(s, string, len); return; } if (iconv(iconv_h, (ICONV_CONST char **) &pin, &i, &pout, &o) == (size_t) - 1) { iconv_close(iconv_h); iconv_h = (iconv_t) - 1; warning("rdp_out_unistr: iconv(1) fail, errno %d\n", errno); g_iconv_works = False; rdp_out_unistr(s, string, len); return; } pin = string; pout = (char *) s->p; } if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1) { iconv_close(iconv_h); iconv_h = (iconv_t) - 1; warning("rdp_out_unistr: iconv(2) fail, errno %d\n", errno); g_iconv_works = False; rdp_out_unistr(s, string, len); return; } s->p += len + 2; } else #endif { int i = 0, j = 0; len += 2; while (i < len) { s->p[i++] = string[j++]; s->p[i++] = 0; } s->p += len; } } /* Input a string in Unicode * * Returns str_len of string */ void rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size) { /* Dynamic allocate of destination string if not provided */ *string = xmalloc(in_len * 2); *str_size = in_len * 2; #ifdef HAVE_ICONV size_t ibl = in_len, obl = *str_size - 1; char *pin = (char *) s->p, *pout = *string; static iconv_t iconv_h = (iconv_t) - 1; if (g_iconv_works) { if (iconv_h == (iconv_t) - 1) { if ((iconv_h = iconv_open(g_codepage, WINDOWS_CODEPAGE)) == (iconv_t) - 1) { warning("rdp_in_unistr: iconv_open[%s -> %s] fail %p\n", WINDOWS_CODEPAGE, g_codepage, iconv_h); g_iconv_works = False; return rdp_in_unistr(s, in_len, string, str_size); } } if (iconv(iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1) { if (errno == E2BIG) { warning("server sent an unexpectedly long string, truncating\n"); } else { warning("rdp_in_unistr: iconv fail, errno %d\n", errno); free(*string); *string = NULL; *str_size = 0; } } /* we must update the location of the current STREAM for future reads of s->p */ s->p += in_len; *pout = 0; if (*string) *str_size = pout - *string; } else #endif { int i = 0; int rem = 0; uint32 len = in_len / 2; if (len > *str_size - 1) { warning("server sent an unexpectedly long string, truncating\n"); len = *str_size - 1; rem = in_len - 2 * len; } while (i < len) { in_uint8a(s, &string[i++], 1); in_uint8s(s, 1); } in_uint8s(s, rem); string[len] = 0; *str_size = len; } } /* Parse a logon info packet */ static void rdp_send_logon_info(uint32 flags, char *domain, char *user, char *password, char *program, char *directory) { char *ipaddr = tcp_get_address(); /* length of string in TS_INFO_PACKET excludes null terminator */ int len_domain = 2 * strlen(domain); int len_user = 2 * strlen(user); int len_password = 2 * strlen(password); int len_program = 2 * strlen(program); int len_directory = 2 * strlen(directory); /* length of strings in TS_EXTENDED_PACKET includes null terminator */ int len_ip = 2 * strlen(ipaddr) + 2; int len_dll = 2 * strlen("C:\\WINNT\\System32\\mstscax.dll") + 2; int packetlen = 0; uint32 sec_flags = g_encryption ? (SEC_LOGON_INFO | SEC_ENCRYPT) : SEC_LOGON_INFO; STREAM s; time_t t = time(NULL); time_t tzone; uint8 security_verifier[16]; if (g_rdp_version == RDP_V4 || 1 == g_server_rdp_version) { DEBUG_RDP5(("Sending RDP4-style Logon packet\n")); s = sec_init(sec_flags, 18 + len_domain + len_user + len_password + len_program + len_directory + 10); out_uint32(s, 0); out_uint32_le(s, flags); out_uint16_le(s, len_domain); out_uint16_le(s, len_user); out_uint16_le(s, len_password); out_uint16_le(s, len_program); out_uint16_le(s, len_directory); rdp_out_unistr(s, domain, len_domain); rdp_out_unistr(s, user, len_user); rdp_out_unistr(s, password, len_password); rdp_out_unistr(s, program, len_program); rdp_out_unistr(s, directory, len_directory); } else { DEBUG_RDP5(("Sending RDP5-style Logon packet\n")); if (g_redirect == True && g_redirect_cookie_len > 0) { len_password = g_redirect_cookie_len; len_password -= 2; /* substract 2 bytes which is added below */ } packetlen = /* size of TS_INFO_PACKET */ 4 + /* CodePage */ 4 + /* flags */ 2 + /* cbDomain */ 2 + /* cbUserName */ 2 + /* cbPassword */ 2 + /* cbAlternateShell */ 2 + /* cbWorkingDir */ 2 + len_domain + /* Domain */ 2 + len_user + /* UserName */ 2 + len_password + /* Password */ 2 + len_program + /* AlternateShell */ 2 + len_directory + /* WorkingDir */ /* size of TS_EXTENDED_INFO_PACKET */ 2 + /* clientAdressFamily */ 2 + /* cbClientAdress */ len_ip + /* clientAddress */ 2 + /* cbClientDir */ len_dll + /* clientDir */ /* size of TS_TIME_ZONE_INFORMATION */ 4 + /* Bias, (UTC = local time + bias */ 64 + /* StandardName, 32 unicode char array, Descriptive standard time on client */ 16 + /* StandardDate */ 4 + /* StandardBias */ 64 + /* DaylightName, 32 unicode char array */ 16 + /* DaylightDate */ 4 + /* DaylightBias */ 4 + /* clientSessionId */ 4 + /* performanceFlags */ 2 + /* cbAutoReconnectCookie, either 0 or 0x001c */ /* size of ARC_CS_PRIVATE_PACKET */ 28; /* autoReconnectCookie */ s = sec_init(sec_flags, packetlen); DEBUG_RDP5(("Called sec_init with packetlen %d\n", packetlen)); /* TS_INFO_PACKET */ out_uint32(s, 0); /* Code Page */ out_uint32_le(s, flags); out_uint16_le(s, len_domain); out_uint16_le(s, len_user); out_uint16_le(s, len_password); out_uint16_le(s, len_program); out_uint16_le(s, len_directory); if (0 < len_domain) rdp_out_unistr(s, domain, len_domain); else out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ if (0 < len_user) rdp_out_unistr(s, user, len_user); else out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ if (0 < len_password) { if (g_redirect == True && 0 < g_redirect_cookie_len) { out_uint8p(s, g_redirect_cookie, g_redirect_cookie_len); } else { rdp_out_unistr(s, password, len_password); } } else out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ if (0 < len_program) rdp_out_unistr(s, program, len_program); else out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ if (0 < len_directory) rdp_out_unistr(s, directory, len_directory); else out_uint16_le(s, 0); /* mandatory 2 bytes null terminator */ /* TS_EXTENDED_INFO_PACKET */ out_uint16_le(s, 2); /* clientAddressFamily = AF_INET */ out_uint16_le(s, len_ip); /* cbClientAddress, Length of client ip */ rdp_out_unistr(s, ipaddr, len_ip - 2); /* clientAddress */ out_uint16_le(s, len_dll); /* cbClientDir */ rdp_out_unistr(s, "C:\\WINNT\\System32\\mstscax.dll", len_dll - 2); /* clientDir */ /* TS_TIME_ZONE_INFORMATION */ tzone = (mktime(gmtime(&t)) - mktime(localtime(&t))) / 60; out_uint32_le(s, tzone); rdp_out_unistr(s, "GTB, normaltid", 2 * strlen("GTB, normaltid")); out_uint8s(s, 62 - 2 * strlen("GTB, normaltid")); out_uint32_le(s, 0x0a0000); out_uint32_le(s, 0x050000); out_uint32_le(s, 3); out_uint32_le(s, 0); out_uint32_le(s, 0); rdp_out_unistr(s, "GTB, sommartid", 2 * strlen("GTB, sommartid")); out_uint8s(s, 62 - 2 * strlen("GTB, sommartid")); out_uint32_le(s, 0x30000); out_uint32_le(s, 0x050000); out_uint32_le(s, 2); out_uint32(s, 0); out_uint32_le(s, 0xffffffc4); /* DaylightBias */ /* Rest of TS_EXTENDED_INFO_PACKET */ out_uint32_le(s, 0); /* clientSessionId (Ignored by server MUST be 0) */ out_uint32_le(s, g_rdp5_performanceflags); /* Client Auto-Reconnect */ if (g_has_reconnect_random) { out_uint16_le(s, 28); /* cbAutoReconnectLen */ /* ARC_CS_PRIVATE_PACKET */ out_uint32_le(s, 28); /* cbLen */ out_uint32_le(s, 1); /* Version */ out_uint32_le(s, g_reconnect_logonid); /* LogonId */ rdssl_hmac_md5(g_reconnect_random, sizeof(g_reconnect_random), g_client_random, SEC_RANDOM_SIZE, security_verifier); out_uint8a(s, security_verifier, sizeof(security_verifier)); } else { out_uint16_le(s, 0); /* cbAutoReconnectLen */ } } s_mark_end(s); /* clear the redirect flag */ g_redirect = False; sec_send(s, sec_flags); } /* Send a control PDU */ static void rdp_send_control(uint16 action) { STREAM s; s = rdp_init_data(8); out_uint16_le(s, action); out_uint16(s, 0); /* userid */ out_uint32(s, 0); /* control id */ s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_CONTROL); } /* Send a synchronisation PDU */ static void rdp_send_synchronise(void) { STREAM s; s = rdp_init_data(4); out_uint16_le(s, 1); /* type */ out_uint16_le(s, 1002); s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_SYNCHRONISE); } /* Send a single input event */ void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2) { STREAM s; s = rdp_init_data(16); out_uint16_le(s, 1); /* number of events */ out_uint16(s, 0); /* pad */ out_uint32_le(s, time); out_uint16_le(s, message_type); out_uint16_le(s, device_flags); out_uint16_le(s, param1); out_uint16_le(s, param2); s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_INPUT); } /* Send a client window information PDU */ void rdp_send_client_window_status(int status) { STREAM s; static int current_status = 1; if (current_status == status) return; s = rdp_init_data(12); out_uint32_le(s, status); switch (status) { case 0: /* shut the server up */ break; case 1: /* receive data again */ out_uint32_le(s, 0); /* unknown */ out_uint16_le(s, g_width); out_uint16_le(s, g_height); break; } s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_CLIENT_WINDOW_STATUS); current_status = status; } /* Send persistent bitmap cache enumeration PDU's */ static void rdp_enum_bmpcache2(void) { STREAM s; HASH_KEY keylist[BMPCACHE2_NUM_PSTCELLS]; uint32 num_keys, offset, count, flags; offset = 0; num_keys = pstcache_enumerate(2, keylist); while (offset < num_keys) { count = MIN(num_keys - offset, 169); s = rdp_init_data(24 + count * sizeof(HASH_KEY)); flags = 0; if (offset == 0) flags |= PDU_FLAG_FIRST; if (num_keys - offset <= 169) flags |= PDU_FLAG_LAST; /* header */ out_uint32_le(s, 0); out_uint16_le(s, count); out_uint16_le(s, 0); out_uint16_le(s, 0); out_uint16_le(s, 0); out_uint16_le(s, 0); out_uint16_le(s, num_keys); out_uint32_le(s, 0); out_uint32_le(s, flags); /* list */ out_uint8a(s, keylist[offset], count * sizeof(HASH_KEY)); s_mark_end(s); rdp_send_data(s, 0x2b); offset += 169; } } /* Send an (empty) font information PDU */ static void rdp_send_fonts(uint16 seq) { STREAM s; s = rdp_init_data(8); out_uint16(s, 0); /* number of fonts */ out_uint16_le(s, 0); /* pad? */ out_uint16_le(s, seq); /* unknown */ out_uint16_le(s, 0x32); /* entry size */ s_mark_end(s); rdp_send_data(s, RDP_DATA_PDU_FONT2); } /* Output general capability set */ static void rdp_out_general_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_GENERAL); out_uint16_le(s, RDP_CAPLEN_GENERAL); out_uint16_le(s, 1); /* OS major type */ out_uint16_le(s, 3); /* OS minor type */ out_uint16_le(s, 0x200); /* Protocol version */ out_uint16(s, 0); /* Pad */ out_uint16(s, 0); /* Compression types */ out_uint16_le(s, (g_rdp_version >= RDP_V5) ? 0x40d : 0); /* Pad, according to T.128. 0x40d seems to trigger the server to start sending RDP5 packets. However, the value is 0x1d04 with W2KTSK and NT4MS. Hmm.. Anyway, thankyou, Microsoft, for sending such information in a padding field.. */ out_uint16(s, 0); /* Update capability */ out_uint16(s, 0); /* Remote unshare capability */ out_uint16(s, 0); /* Compression level */ out_uint16(s, 0); /* Pad */ } /* Output bitmap capability set */ static void rdp_out_bitmap_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_BITMAP); out_uint16_le(s, RDP_CAPLEN_BITMAP); out_uint16_le(s, g_server_depth); /* Preferred colour depth */ out_uint16_le(s, 1); /* Receive 1 BPP */ out_uint16_le(s, 1); /* Receive 4 BPP */ out_uint16_le(s, 1); /* Receive 8 BPP */ out_uint16_le(s, 800); /* Desktop width */ out_uint16_le(s, 600); /* Desktop height */ out_uint16(s, 0); /* Pad */ out_uint16(s, 1); /* Allow resize */ out_uint16_le(s, g_bitmap_compression ? 1 : 0); /* Support compression */ out_uint16(s, 0); /* Unknown */ out_uint16_le(s, 1); /* Unknown */ out_uint16(s, 0); /* Pad */ } /* Output order capability set */ static void rdp_out_order_caps(STREAM s) { uint8 order_caps[32]; memset(order_caps, 0, 32); order_caps[0] = 1; /* dest blt */ order_caps[1] = 1; /* pat blt */ order_caps[2] = 1; /* screen blt */ order_caps[3] = (g_bitmap_cache ? 1 : 0); /* memblt */ order_caps[4] = 0; /* triblt */ order_caps[8] = 1; /* line */ order_caps[9] = 1; /* line */ order_caps[10] = 1; /* rect */ order_caps[11] = (g_desktop_save ? 1 : 0); /* desksave */ order_caps[13] = 1; /* memblt */ order_caps[14] = 1; /* triblt */ order_caps[20] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon */ order_caps[21] = (g_polygon_ellipse_orders ? 1 : 0); /* polygon2 */ order_caps[22] = 1; /* polyline */ order_caps[25] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse */ order_caps[26] = (g_polygon_ellipse_orders ? 1 : 0); /* ellipse2 */ order_caps[27] = 1; /* text2 */ out_uint16_le(s, RDP_CAPSET_ORDER); out_uint16_le(s, RDP_CAPLEN_ORDER); out_uint8s(s, 20); /* Terminal desc, pad */ out_uint16_le(s, 1); /* Cache X granularity */ out_uint16_le(s, 20); /* Cache Y granularity */ out_uint16(s, 0); /* Pad */ out_uint16_le(s, 1); /* Max order level */ out_uint16_le(s, 0x147); /* Number of fonts */ out_uint16_le(s, 0x2a); /* Capability flags */ out_uint8p(s, order_caps, 32); /* Orders supported */ out_uint16_le(s, 0x6a1); /* Text capability flags */ out_uint8s(s, 6); /* Pad */ out_uint32_le(s, g_desktop_save == False ? 0 : 0x38400); /* Desktop cache size */ out_uint32(s, 0); /* Unknown */ out_uint32_le(s, 0x4e4); /* Unknown */ } /* Output bitmap cache capability set */ static void rdp_out_bmpcache_caps(STREAM s) { int Bpp; out_uint16_le(s, RDP_CAPSET_BMPCACHE); out_uint16_le(s, RDP_CAPLEN_BMPCACHE); Bpp = (g_server_depth + 7) / 8; /* bytes per pixel */ out_uint8s(s, 24); /* unused */ out_uint16_le(s, 0x258); /* entries */ out_uint16_le(s, 0x100 * Bpp); /* max cell size */ out_uint16_le(s, 0x12c); /* entries */ out_uint16_le(s, 0x400 * Bpp); /* max cell size */ out_uint16_le(s, 0x106); /* entries */ out_uint16_le(s, 0x1000 * Bpp); /* max cell size */ } /* Output bitmap cache v2 capability set */ static void rdp_out_bmpcache2_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_BMPCACHE2); out_uint16_le(s, RDP_CAPLEN_BMPCACHE2); out_uint16_le(s, g_bitmap_cache_persist_enable ? 2 : 0); /* version */ out_uint16_be(s, 3); /* number of caches in this set */ /* max cell size for cache 0 is 16x16, 1 = 32x32, 2 = 64x64, etc */ out_uint32_le(s, BMPCACHE2_C0_CELLS); out_uint32_le(s, BMPCACHE2_C1_CELLS); if (pstcache_init(2)) { out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST); } else { out_uint32_le(s, BMPCACHE2_C2_CELLS); } out_uint8s(s, 20); /* other bitmap caches not used */ } /* Output control capability set */ static void rdp_out_control_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_CONTROL); out_uint16_le(s, RDP_CAPLEN_CONTROL); out_uint16(s, 0); /* Control capabilities */ out_uint16(s, 0); /* Remote detach */ out_uint16_le(s, 2); /* Control interest */ out_uint16_le(s, 2); /* Detach interest */ } /* Output activation capability set */ static void rdp_out_activate_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_ACTIVATE); out_uint16_le(s, RDP_CAPLEN_ACTIVATE); out_uint16(s, 0); /* Help key */ out_uint16(s, 0); /* Help index key */ out_uint16(s, 0); /* Extended help key */ out_uint16(s, 0); /* Window activate */ } /* Output pointer capability set */ static void rdp_out_pointer_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_POINTER); out_uint16_le(s, RDP_CAPLEN_POINTER); out_uint16(s, 0); /* Colour pointer */ out_uint16_le(s, 20); /* Cache size */ } /* Output new pointer capability set */ static void rdp_out_newpointer_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_POINTER); out_uint16_le(s, RDP_CAPLEN_NEWPOINTER); out_uint16_le(s, 1); /* Colour pointer */ out_uint16_le(s, 20); /* Cache size */ out_uint16_le(s, 20); /* Cache size for new pointers */ } /* Output share capability set */ static void rdp_out_share_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_SHARE); out_uint16_le(s, RDP_CAPLEN_SHARE); out_uint16(s, 0); /* userid */ out_uint16(s, 0); /* pad */ } /* Output colour cache capability set */ static void rdp_out_colcache_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_COLCACHE); out_uint16_le(s, RDP_CAPLEN_COLCACHE); out_uint16_le(s, 6); /* cache size */ out_uint16(s, 0); /* pad */ } /* Output brush cache capability set */ static void rdp_out_brushcache_caps(STREAM s) { out_uint16_le(s, RDP_CAPSET_BRUSHCACHE); out_uint16_le(s, RDP_CAPLEN_BRUSHCACHE); out_uint32_le(s, 1); /* cache type */ } static uint8 caps_0x0d[] = { 0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 }; static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 }; static uint8 caps_0x10[] = { 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00, 0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00, 0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00 }; /* Output unknown capability sets */ static void rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 * caps) { out_uint16_le(s, id); out_uint16_le(s, length); out_uint8p(s, caps, length - 4); } #define RDP5_FLAG 0x0030 /* Send a confirm active PDU */ static void rdp_send_confirm_active(void) { STREAM s; uint32 sec_flags = g_encryption ? (RDP5_FLAG | SEC_ENCRYPT) : RDP5_FLAG; uint16 caplen = RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER + RDP_CAPLEN_COLCACHE + RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + RDP_CAPLEN_SHARE + RDP_CAPLEN_BRUSHCACHE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + 4 /* w2k fix, sessionid */ ; if (g_rdp_version >= RDP_V5) { caplen += RDP_CAPLEN_BMPCACHE2; caplen += RDP_CAPLEN_NEWPOINTER; } else { caplen += RDP_CAPLEN_BMPCACHE; caplen += RDP_CAPLEN_POINTER; } s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE)); out_uint16_le(s, 2 + 14 + caplen + sizeof(RDP_SOURCE)); out_uint16_le(s, (RDP_PDU_CONFIRM_ACTIVE | 0x10)); /* Version 1 */ out_uint16_le(s, (g_mcs_userid + 1001)); out_uint32_le(s, g_rdp_shareid); out_uint16_le(s, 0x3ea); /* userid */ out_uint16_le(s, sizeof(RDP_SOURCE)); out_uint16_le(s, caplen); out_uint8p(s, RDP_SOURCE, sizeof(RDP_SOURCE)); out_uint16_le(s, 0xe); /* num_caps */ out_uint8s(s, 2); /* pad */ rdp_out_general_caps(s); rdp_out_bitmap_caps(s); rdp_out_order_caps(s); if (g_rdp_version >= RDP_V5) { rdp_out_bmpcache2_caps(s); rdp_out_newpointer_caps(s); } else { rdp_out_bmpcache_caps(s); rdp_out_pointer_caps(s); } rdp_out_colcache_caps(s); rdp_out_activate_caps(s); rdp_out_control_caps(s); rdp_out_share_caps(s); rdp_out_brushcache_caps(s); rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* CAPSTYPE_INPUT */ rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c); /* CAPSTYPE_SOUND */ rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e); /* CAPSTYPE_FONT */ rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* CAPSTYPE_GLYPHCACHE */ s_mark_end(s); sec_send(s, sec_flags); } /* Process a general capability set */ static void rdp_process_general_caps(STREAM s) { uint16 pad2octetsB; /* rdp5 flags? */ in_uint8s(s, 10); in_uint16_le(s, pad2octetsB); if (!pad2octetsB) g_rdp_version = RDP_V4; } /* Process a bitmap capability set */ static void rdp_process_bitmap_caps(STREAM s) { uint16 width, height, depth; in_uint16_le(s, depth); in_uint8s(s, 6); in_uint16_le(s, width); in_uint16_le(s, height); DEBUG(("setting desktop size and depth to: %dx%dx%d\n", width, height, depth)); /* * The server may limit depth and change the size of the desktop (for * example when shadowing another session). */ if (g_server_depth != depth) { warning("Remote desktop does not support colour depth %d; falling back to %d\n", g_server_depth, depth); g_server_depth = depth; } if (g_width != width || g_height != height) { warning("Remote desktop changed from %dx%d to %dx%d.\n", g_width, g_height, width, height); g_width = width; g_height = height; ui_resize_window(); } } /* Process server capabilities */ static void rdp_process_server_caps(STREAM s, uint16 length) { int n; uint8 *next, *start; uint16 ncapsets, capset_type, capset_length; start = s->p; in_uint16_le(s, ncapsets); in_uint8s(s, 2); /* pad */ for (n = 0; n < ncapsets; n++) { if (s->p > start + length) return; in_uint16_le(s, capset_type); in_uint16_le(s, capset_length); next = s->p + capset_length - 4; switch (capset_type) { case RDP_CAPSET_GENERAL: rdp_process_general_caps(s); break; case RDP_CAPSET_BITMAP: rdp_process_bitmap_caps(s); break; } s->p = next; } } /* Respond to a demand active PDU */ static void process_demand_active(STREAM s) { uint8 type; uint16 len_src_descriptor, len_combined_caps; /* at this point we need to ensure that we have ui created */ rd_create_ui(); in_uint32_le(s, g_rdp_shareid); in_uint16_le(s, len_src_descriptor); in_uint16_le(s, len_combined_caps); in_uint8s(s, len_src_descriptor); DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid)); rdp_process_server_caps(s, len_combined_caps); rdp_send_confirm_active(); rdp_send_synchronise(); rdp_send_control(RDP_CTL_COOPERATE); rdp_send_control(RDP_CTL_REQUEST_CONTROL); rdp_recv(&type); /* RDP_PDU_SYNCHRONIZE */ rdp_recv(&type); /* RDP_CTL_COOPERATE */ rdp_recv(&type); /* RDP_CTL_GRANT_CONTROL */ rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, g_numlock_sync ? ui_get_numlock_state(read_keyboard_state()) : 0, 0); if (g_rdp_version >= RDP_V5) { rdp_enum_bmpcache2(); rdp_send_fonts(3); } else { rdp_send_fonts(1); rdp_send_fonts(2); } rdp_recv(&type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */ reset_order_state(); } /* Process a colour pointer PDU */ static void process_colour_pointer_common(STREAM s, int bpp) { uint16 width, height, cache_idx, masklen, datalen; uint16 x, y; uint8 *mask; uint8 *data; RD_HCURSOR cursor; in_uint16_le(s, cache_idx); in_uint16_le(s, x); in_uint16_le(s, y); in_uint16_le(s, width); in_uint16_le(s, height); in_uint16_le(s, masklen); in_uint16_le(s, datalen); in_uint8p(s, data, datalen); in_uint8p(s, mask, masklen); if ((width != 32) || (height != 32)) { warning("process_colour_pointer_common: " "width %d height %d\n", width, height); } /* keep hotspot within cursor bounding box */ x = MIN(x, width - 1); y = MIN(y, height - 1); cursor = ui_create_cursor(x, y, width, height, mask, data, bpp); ui_set_cursor(cursor); cache_put_cursor(cache_idx, cursor); } /* Process a colour pointer PDU */ void process_colour_pointer_pdu(STREAM s) { process_colour_pointer_common(s, 24); } /* Process a New Pointer PDU - these pointers have variable bit depth */ void process_new_pointer_pdu(STREAM s) { int xor_bpp; in_uint16_le(s, xor_bpp); process_colour_pointer_common(s, xor_bpp); } /* Process a cached pointer PDU */ void process_cached_pointer_pdu(STREAM s) { uint16 cache_idx; in_uint16_le(s, cache_idx); ui_set_cursor(cache_get_cursor(cache_idx)); } /* Process a system pointer PDU */ void process_system_pointer_pdu(STREAM s) { uint16 system_pointer_type; in_uint16_le(s, system_pointer_type); switch (system_pointer_type) { case RDP_NULL_POINTER: ui_set_null_cursor(); break; default: unimpl("System pointer message 0x%x\n", system_pointer_type); } } /* Process a pointer PDU */ static void process_pointer_pdu(STREAM s) { uint16 message_type; uint16 x, y; in_uint16_le(s, message_type); in_uint8s(s, 2); /* pad */ switch (message_type) { case RDP_POINTER_MOVE: in_uint16_le(s, x); in_uint16_le(s, y); if (s_check(s)) ui_move_pointer(x, y); break; case RDP_POINTER_COLOR: process_colour_pointer_pdu(s); break; case RDP_POINTER_CACHED: process_cached_pointer_pdu(s); break; case RDP_POINTER_SYSTEM: process_system_pointer_pdu(s); break; case RDP_POINTER_NEW: process_new_pointer_pdu(s); break; default: unimpl("Pointer message 0x%x\n", message_type); } } /* Process bitmap updates */ void process_bitmap_updates(STREAM s) { uint16 num_updates; uint16 left, top, right, bottom, width, height; uint16 cx, cy, bpp, Bpp, compress, bufsize, size; uint8 *data, *bmpdata; int i; in_uint16_le(s, num_updates); for (i = 0; i < num_updates; i++) { in_uint16_le(s, left); in_uint16_le(s, top); in_uint16_le(s, right); in_uint16_le(s, bottom); in_uint16_le(s, width); in_uint16_le(s, height); in_uint16_le(s, bpp); Bpp = (bpp + 7) / 8; in_uint16_le(s, compress); in_uint16_le(s, bufsize); cx = right - left + 1; cy = bottom - top + 1; DEBUG(("BITMAP_UPDATE(l=%d,t=%d,r=%d,b=%d,w=%d,h=%d,Bpp=%d,cmp=%d)\n", left, top, right, bottom, width, height, Bpp, compress)); if (!compress) { int y; bmpdata = (uint8 *) xmalloc(width * height * Bpp); for (y = 0; y < height; y++) { in_uint8a(s, &bmpdata[(height - y - 1) * (width * Bpp)], width * Bpp); } ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata); xfree(bmpdata); continue; } if (compress & 0x400) { size = bufsize; } else { in_uint8s(s, 2); /* pad */ in_uint16_le(s, size); in_uint8s(s, 4); /* line_size, final_size */ } in_uint8p(s, data, size); bmpdata = (uint8 *) xmalloc(width * height * Bpp); if (bitmap_decompress(bmpdata, width, height, data, size, Bpp)) { ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata); } else { DEBUG_RDP5(("Failed to decompress data\n")); } xfree(bmpdata); } } /* Process a palette update */ void process_palette(STREAM s) { COLOURENTRY *entry; COLOURMAP map; RD_HCOLOURMAP hmap; int i; in_uint8s(s, 2); /* pad */ in_uint16_le(s, map.ncolours); in_uint8s(s, 2); /* pad */ map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours); DEBUG(("PALETTE(c=%d)\n", map.ncolours)); for (i = 0; i < map.ncolours; i++) { entry = &map.colours[i]; in_uint8(s, entry->red); in_uint8(s, entry->green); in_uint8(s, entry->blue); } hmap = ui_create_colourmap(&map); ui_set_colourmap(hmap); xfree(map.colours); } /* Process an update PDU */ static void process_update_pdu(STREAM s) { uint16 update_type, count; in_uint16_le(s, update_type); ui_begin_update(); switch (update_type) { case RDP_UPDATE_ORDERS: in_uint8s(s, 2); /* pad */ in_uint16_le(s, count); in_uint8s(s, 2); /* pad */ process_orders(s, count); break; case RDP_UPDATE_BITMAP: process_bitmap_updates(s); break; case RDP_UPDATE_PALETTE: process_palette(s); break; case RDP_UPDATE_SYNCHRONIZE: break; default: unimpl("update %d\n", update_type); } ui_end_update(); } /* Process a Save Session Info PDU */ void process_pdu_logon(STREAM s) { uint32 infotype; in_uint32_le(s, infotype); if (infotype == INFOTYPE_LOGON_EXTENDED_INF) { uint32 fieldspresent; in_uint8s(s, 2); /* Length */ in_uint32_le(s, fieldspresent); if (fieldspresent & LOGON_EX_AUTORECONNECTCOOKIE) { uint32 len; uint32 version; /* TS_LOGON_INFO_FIELD */ in_uint8s(s, 4); /* cbFieldData */ /* ARC_SC_PRIVATE_PACKET */ in_uint32_le(s, len); if (len != 28) { warning("Invalid length in Auto-Reconnect packet\n"); return; } in_uint32_le(s, version); if (version != 1) { warning("Unsupported version of Auto-Reconnect packet\n"); return; } in_uint32_le(s, g_reconnect_logonid); in_uint8a(s, g_reconnect_random, 16); g_has_reconnect_random = True; g_reconnect_random_ts = time(NULL); DEBUG(("Saving auto-reconnect cookie, id=%u\n", g_reconnect_logonid)); } } } /* Process a disconnect PDU */ void process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason) { in_uint32_le(s, *ext_disc_reason); DEBUG(("Received disconnect PDU\n")); } /* Process data PDU */ static RD_BOOL process_data_pdu(STREAM s, uint32 * ext_disc_reason) { uint8 data_pdu_type; uint8 ctype; uint16 clen; uint32 len; uint32 roff, rlen; struct stream *ns = &(g_mppc_dict.ns); in_uint8s(s, 6); /* shareid, pad, streamid */ in_uint16_le(s, len); in_uint8(s, data_pdu_type); in_uint8(s, ctype); in_uint16_le(s, clen); clen -= 18; if (ctype & RDP_MPPC_COMPRESSED) { if (len > RDP_MPPC_DICT_SIZE) error("error decompressed packet size exceeds max\n"); if (mppc_expand(s->p, clen, ctype, &roff, &rlen) == -1) error("error while decompressing packet\n"); /* len -= 18; */ /* allocate memory and copy the uncompressed data into the temporary stream */ ns->data = (uint8 *) xrealloc(ns->data, rlen); memcpy((ns->data), (unsigned char *) (g_mppc_dict.hist + roff), rlen); ns->size = rlen; ns->end = (ns->data + ns->size); ns->p = ns->data; ns->rdp_hdr = ns->p; s = ns; } switch (data_pdu_type) { case RDP_DATA_PDU_UPDATE: process_update_pdu(s); break; case RDP_DATA_PDU_CONTROL: DEBUG(("Received Control PDU\n")); break; case RDP_DATA_PDU_SYNCHRONISE: DEBUG(("Received Sync PDU\n")); break; case RDP_DATA_PDU_POINTER: process_pointer_pdu(s); break; case RDP_DATA_PDU_BELL: ui_bell(); break; case RDP_DATA_PDU_LOGON: DEBUG(("Received Logon PDU\n")); /* User logged on */ process_pdu_logon(s); break; case RDP_DATA_PDU_DISCONNECT: process_disconnect_pdu(s, ext_disc_reason); /* We used to return true and disconnect immediately here, but * Windows Vista sends a disconnect PDU with reason 0 when * reconnecting to a disconnected session, and MSTSC doesn't * drop the connection. I think we should just save the status. */ break; case RDP_DATA_PDU_AUTORECONNECT_STATUS: warning("Automatic reconnect using cookie, failed.\n"); break; default: unimpl("data PDU %d\n", data_pdu_type); } return False; } /* Process redirect PDU from Session Directory */ static RD_BOOL process_redirect_pdu(STREAM s, RD_BOOL enhanced_redirect /*, uint32 * ext_disc_reason */ ) { uint32 len; uint16 redirect_identifier; /* reset any previous redirection information */ g_redirect = True; free(g_redirect_server); free(g_redirect_username); free(g_redirect_domain); free(g_redirect_lb_info); free(g_redirect_cookie); g_redirect_server = NULL; g_redirect_username = NULL; g_redirect_domain = NULL; g_redirect_lb_info = NULL; g_redirect_cookie = NULL; /* these 2 bytes are unknown, seem to be zeros */ in_uint8s(s, 2); /* FIXME: Previous implementation only reads 4 bytes which has been working but todays spec says something different. Investigate and retest server redirection using WTS 2003 cluster. */ if (enhanced_redirect) { /* read identifier */ in_uint16_le(s, redirect_identifier); if (redirect_identifier != 0x0400) error("Protocol error in server redirection, unexpected data."); /* FIXME: skip total length */ in_uint8s(s, 2); /* read session_id */ in_uint32_le(s, g_redirect_session_id); } /* read connection flags */ in_uint32_le(s, g_redirect_flags); if (g_redirect_flags & PDU_REDIRECT_HAS_IP) { /* read length of ip string */ in_uint32_le(s, len); /* read ip string */ rdp_in_unistr(s, len, &g_redirect_server, &g_redirect_server_len); } if (g_redirect_flags & PDU_REDIRECT_HAS_LOAD_BALANCE_INFO) { /* read length of load balance info blob */ in_uint32_le(s, g_redirect_lb_info_len); /* reallocate a loadbalance info blob */ if (g_redirect_lb_info != NULL) free(g_redirect_lb_info); g_redirect_lb_info = xmalloc(g_redirect_lb_info_len); /* read load balance info blob */ in_uint8p(s, g_redirect_lb_info, g_redirect_lb_info_len); } if (g_redirect_flags & PDU_REDIRECT_HAS_USERNAME) { /* read length of username string */ in_uint32_le(s, len); /* read username string */ rdp_in_unistr(s, len, &g_redirect_username, &g_redirect_username_len); } if (g_redirect_flags & PDU_REDIRECT_HAS_DOMAIN) { /* read length of domain string */ in_uint32_le(s, len); /* read domain string */ rdp_in_unistr(s, len, &g_redirect_domain, &g_redirect_domain_len); } if (g_redirect_flags & PDU_REDIRECT_HAS_PASSWORD) { /* the information in this blob is either a password or a cookie that should be passed though as blob and not parsed as a unicode string */ /* read blob length */ in_uint32_le(s, g_redirect_cookie_len); /* reallocate cookie blob */ if (g_redirect_cookie != NULL) free(g_redirect_cookie); g_redirect_cookie = xmalloc(g_redirect_cookie_len); /* read cookie as is */ in_uint8p(s, g_redirect_cookie, g_redirect_cookie_len); } if (g_redirect_flags & PDU_REDIRECT_DONT_STORE_USERNAME) { warning("PDU_REDIRECT_DONT_STORE_USERNAME set\n"); } if (g_redirect_flags & PDU_REDIRECT_USE_SMARTCARD) { warning("PDU_REDIRECT_USE_SMARTCARD set\n"); } if (g_redirect_flags & PDU_REDIRECT_INFORMATIONAL) { /* By spec this is only for information and doesn't mean that an actual redirect should be performed. How it should be used is not mentioned. */ g_redirect = False; } if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_FQDN) { in_uint32_le(s, len); /* Let target fqdn replace target ip address */ if (g_redirect_server) { free(g_redirect_server); g_redirect_server = NULL; } /* read fqdn string */ rdp_in_unistr(s, len, &g_redirect_server, &g_redirect_server_len); } if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_NETBIOS) { warning("PDU_REDIRECT_HAS_TARGET_NETBIOS set\n"); } if (g_redirect_flags & PDU_REDIRECT_HAS_TARGET_IP_ARRAY) { warning("PDU_REDIRECT_HAS_TARGET_IP_ARRAY set\n"); } return True; } /* Process incoming packets */ void rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { while (rdp_loop(deactivated, ext_disc_reason)) { if (g_pending_resize || g_redirect) { return; } } } /* used in uiports and rdp_main_loop, processes the rdp packets waiting */ RD_BOOL rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) { uint8 type; RD_BOOL cont = True; STREAM s; while (cont) { s = rdp_recv(&type); if (s == NULL) return False; switch (type) { case RDP_PDU_DEMAND_ACTIVE: process_demand_active(s); *deactivated = False; break; case RDP_PDU_DEACTIVATE: DEBUG(("RDP_PDU_DEACTIVATE\n")); *deactivated = True; break; case RDP_PDU_REDIRECT: return process_redirect_pdu(s, False); break; case RDP_PDU_ENHANCED_REDIRECT: return process_redirect_pdu(s, True); break; case RDP_PDU_DATA: /* If we got a data PDU, we don't need to keep the password in memory anymore and therefor we should clear it for security reasons. */ if (g_password[0] != '\0') memset(g_password, 0, sizeof(g_password)); process_data_pdu(s, ext_disc_reason); break; case 0: break; default: unimpl("PDU %d\n", type); } cont = g_next_packet < s->end; } return True; } /* Establish a connection up to the RDP layer */ RD_BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, char *directory, RD_BOOL reconnect) { RD_BOOL deactivated = False; uint32 ext_disc_reason = 0; if (!sec_connect(server, g_username, domain, password, reconnect)) return False; rdp_send_logon_info(flags, domain, g_username, password, command, directory); /* run RDP loop until first licence demand active PDU */ while (!g_rdp_shareid) { if (g_network_error) return False; if (!rdp_loop(&deactivated, &ext_disc_reason)) return False; if (g_redirect) return True; } return True; } /* Called during redirection to reset the state to support redirection */ void rdp_reset_state(void) { g_next_packet = NULL; /* reset the packet information */ g_rdp_shareid = 0; sec_reset_state(); } /* Disconnect from the RDP layer */ void rdp_disconnect(void) { sec_disconnect(); } rdesktop-1.8.3/rdpdr.c0000664000770100510440000006732312404306606013570 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Copyright (C) Matthew Chapman 1999-2008 Copyright 2004-2011 Peter Astrand for Cendio AB Copyright 2010-2014 Henrik Andersson for Cendio AB 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 3 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, see . */ /* Here are some resources, for your IRP hacking pleasure: http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/winddk.h?view=markup http://win32.mvps.org/ntfs/streams.cpp http://www.acc.umu.se/~bosse/ntifs.h http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/ http://us1.samba.org/samba/ftp/specs/smb-nt01.txt http://www.osronline.com/ */ #include #include #include #include /* opendir, closedir, readdir */ #include #include #include "rdesktop.h" #define IRP_MJ_CREATE 0x00 #define IRP_MJ_CLOSE 0x02 #define IRP_MJ_READ 0x03 #define IRP_MJ_WRITE 0x04 #define IRP_MJ_QUERY_INFORMATION 0x05 #define IRP_MJ_SET_INFORMATION 0x06 #define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a #define IRP_MJ_DIRECTORY_CONTROL 0x0c #define IRP_MJ_DEVICE_CONTROL 0x0e #define IRP_MJ_LOCK_CONTROL 0x11 #define IRP_MN_QUERY_DIRECTORY 0x01 #define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02 extern char g_hostname[16]; extern DEVICE_FNS serial_fns; extern DEVICE_FNS printer_fns; extern DEVICE_FNS parallel_fns; extern DEVICE_FNS disk_fns; #ifdef WITH_SCARD extern DEVICE_FNS scard_fns; #endif extern FILEINFO g_fileinfo[]; extern RD_BOOL g_notify_stamp; static VCHANNEL *rdpdr_channel; static uint32 g_epoch; /* If select() times out, the request for the device with handle g_min_timeout_fd is aborted */ RD_NTHANDLE g_min_timeout_fd; uint32 g_num_devices; uint32 g_client_id; /* Table with information about rdpdr devices */ RDPDR_DEVICE g_rdpdr_device[RDPDR_MAX_DEVICES]; char *g_rdpdr_clientname = NULL; /* Used to store incoming io request, until they are ready to be completed */ /* using a linked list ensures that they are processed in the right order, */ /* if multiple ios are being done on the same fd */ struct async_iorequest { uint32 fd, major, minor, offset, device, id, length, partial_len; long timeout, /* Total timeout */ itv_timeout; /* Interval timeout (between serial characters) */ uint8 *buffer; DEVICE_FNS *fns; struct async_iorequest *next; /* next element in list */ }; struct async_iorequest *g_iorequest; /* Return device_id for a given handle */ int get_device_index(RD_NTHANDLE handle) { int i; for (i = 0; i < RDPDR_MAX_DEVICES; i++) { if (g_rdpdr_device[i].handle == handle) return i; } return -1; } /* Converts a windows path to a unix path */ void convert_to_unix_filename(char *filename) { char *p; while ((p = strchr(filename, '\\'))) { *p = '/'; } } static RD_BOOL rdpdr_handle_ok(int device, int handle) { switch (g_rdpdr_device[device].device_type) { case DEVICE_TYPE_PARALLEL: case DEVICE_TYPE_SERIAL: case DEVICE_TYPE_PRINTER: case DEVICE_TYPE_SCARD: if (g_rdpdr_device[device].handle != handle) return False; break; case DEVICE_TYPE_DISK: if (g_fileinfo[handle].device_id != device) return False; break; } return True; } /* Add a new io request to the table containing pending io requests so it won't block rdesktop */ static RD_BOOL add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length, DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer, uint32 offset) { struct async_iorequest *iorq; if (g_iorequest == NULL) { g_iorequest = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest)); if (!g_iorequest) return False; g_iorequest->fd = 0; g_iorequest->next = NULL; } iorq = g_iorequest; while (iorq->fd != 0) { /* create new element if needed */ if (iorq->next == NULL) { iorq->next = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest)); if (!iorq->next) return False; iorq->next->fd = 0; iorq->next->next = NULL; } iorq = iorq->next; } iorq->device = device; iorq->fd = file; iorq->id = id; iorq->major = major; iorq->length = length; iorq->partial_len = 0; iorq->fns = fns; iorq->timeout = total_timeout; iorq->itv_timeout = interval_timeout; iorq->buffer = buffer; iorq->offset = offset; return True; } static void rdpdr_send_client_announce_reply(void) { /* DR_CORE_CLIENT_ANNOUNCE_RSP */ STREAM s; s = channel_init(rdpdr_channel, 12); out_uint16_le(s, RDPDR_CTYP_CORE); out_uint16_le(s, PAKID_CORE_CLIENTID_CONFIRM); out_uint16_le(s, 1); /* VersionMajor, MUST be set to 0x1 */ out_uint16_le(s, 5); /* VersionMinor */ out_uint32_be(s, g_client_id); /* ClientID */ s_mark_end(s); channel_send(s, rdpdr_channel); } static void rdpdr_send_client_name_request(void) { /* DR_CORE_CLIENT_NAME_REQ */ STREAM s; uint32 hostlen; if (NULL == g_rdpdr_clientname) { g_rdpdr_clientname = g_hostname; } hostlen = (strlen(g_rdpdr_clientname) + 1) * 2; s = channel_init(rdpdr_channel, 16 + hostlen); out_uint16_le(s, RDPDR_CTYP_CORE); out_uint16_le(s, PAKID_CORE_CLIENT_NAME); out_uint32_le(s, 1); /* UnicodeFlag */ out_uint32_le(s, 0); /* CodePage */ out_uint32_le(s, hostlen); /* ComputerNameLen */ rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2); s_mark_end(s); channel_send(s, rdpdr_channel); } /* Returns the size of the payload of the announce packet */ static int announcedata_size() { int size, i; PRINTER *printerinfo; size = 8; /* static announce size */ size += g_num_devices * 0x14; for (i = 0; i < g_num_devices; i++) { if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER) { printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data; printerinfo->bloblen = printercache_load_blob(printerinfo->printer, &(printerinfo->blob)); size += 0x18; size += 2 * strlen(printerinfo->driver) + 2; size += 2 * strlen(printerinfo->printer) + 2; size += printerinfo->bloblen; } } return size; } static void rdpdr_send_client_device_list_announce(void) { /* DR_CORE_CLIENT_ANNOUNCE_RSP */ uint32 driverlen, printerlen, bloblen; int i; STREAM s; PRINTER *printerinfo; s = channel_init(rdpdr_channel, announcedata_size()); out_uint16_le(s, RDPDR_CTYP_CORE); out_uint16_le(s, PAKID_CORE_DEVICE_LIST_ANNOUNCE); out_uint32_le(s, g_num_devices); for (i = 0; i < g_num_devices; i++) { out_uint32_le(s, g_rdpdr_device[i].device_type); out_uint32_le(s, i); /* RDP Device ID */ /* Is it possible to use share names longer than 8 chars? /astrand */ out_uint8p(s, g_rdpdr_device[i].name, 8); switch (g_rdpdr_device[i].device_type) { case DEVICE_TYPE_PRINTER: printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data; driverlen = 2 * strlen(printerinfo->driver) + 2; printerlen = 2 * strlen(printerinfo->printer) + 2; bloblen = printerinfo->bloblen; out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */ out_uint32_le(s, printerinfo->default_printer ? 2 : 0); out_uint8s(s, 8); /* unknown */ out_uint32_le(s, driverlen); out_uint32_le(s, printerlen); out_uint32_le(s, bloblen); rdp_out_unistr(s, printerinfo->driver, driverlen - 2); rdp_out_unistr(s, printerinfo->printer, printerlen - 2); out_uint8a(s, printerinfo->blob, bloblen); if (printerinfo->blob) xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */ break; default: out_uint32(s, 0); } } s_mark_end(s); channel_send(s, rdpdr_channel); } void rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer, uint32 length) { STREAM s; #ifdef WITH_SCARD scard_lock(SCARD_LOCK_RDPDR); #endif s = channel_init(rdpdr_channel, 20 + length); out_uint16_le(s, RDPDR_CTYP_CORE); out_uint16_le(s, PAKID_CORE_DEVICE_IOCOMPLETION); out_uint32_le(s, device); out_uint32_le(s, id); out_uint32_le(s, status); out_uint32_le(s, result); out_uint8p(s, buffer, length); s_mark_end(s); /* JIF */ #ifdef WITH_DEBUG_RDP5 printf("--> rdpdr_send_completion\n"); /* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */ #endif channel_send(s, rdpdr_channel); #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_RDPDR); #endif } static void rdpdr_process_irp(STREAM s) { uint32 result = 0, length = 0, desired_access = 0, request, file, info_level, buffer_len, id, major, minor, device, offset, bytes_in, bytes_out, error_mode, share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0; char *filename; uint32 filename_len; uint8 *buffer, *pst_buf; struct stream out; DEVICE_FNS *fns; RD_BOOL rw_blocking = True; RD_NTSTATUS status = RD_STATUS_INVALID_DEVICE_REQUEST; in_uint32_le(s, device); in_uint32_le(s, file); in_uint32_le(s, id); in_uint32_le(s, major); in_uint32_le(s, minor); filename = NULL; buffer_len = 0; buffer = (uint8 *) xmalloc(1024); buffer[0] = 0; if (device >= RDPDR_MAX_DEVICES) { error("invalid irp device 0x%lx file 0x%lx id 0x%lx major 0x%lx minor 0x%lx\n", device, file, id, major, minor); xfree(buffer); return; } switch (g_rdpdr_device[device].device_type) { case DEVICE_TYPE_SERIAL: fns = &serial_fns; rw_blocking = False; break; case DEVICE_TYPE_PARALLEL: fns = ¶llel_fns; rw_blocking = False; break; case DEVICE_TYPE_PRINTER: fns = &printer_fns; break; case DEVICE_TYPE_DISK: fns = &disk_fns; rw_blocking = False; break; case DEVICE_TYPE_SCARD: #ifdef WITH_SCARD fns = &scard_fns; rw_blocking = False; break; #endif default: error("IRP for bad device %ld\n", device); xfree(buffer); return; } switch (major) { case IRP_MJ_CREATE: in_uint32_be(s, desired_access); in_uint8s(s, 0x08); /* unknown */ in_uint32_le(s, error_mode); in_uint32_le(s, share_mode); in_uint32_le(s, disposition); in_uint32_le(s, flags_and_attributes); in_uint32_le(s, length); if (length && (length / 2) < 256) { rdp_in_unistr(s, length, &filename, &filename_len); if (filename) convert_to_unix_filename(filename); } if (!fns->create) { status = RD_STATUS_NOT_SUPPORTED; free(filename); break; } status = fns->create(device, desired_access, share_mode, disposition, flags_and_attributes, filename, &result); free(filename); buffer_len = 1; break; case IRP_MJ_CLOSE: if (!fns->close) { status = RD_STATUS_NOT_SUPPORTED; break; } status = fns->close(file); break; case IRP_MJ_READ: if (!fns->read) { status = RD_STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, length); in_uint32_le(s, offset); #if WITH_DEBUG_RDP5 DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset)); #endif if (!rdpdr_handle_ok(device, file)) { status = RD_STATUS_INVALID_HANDLE; break; } if (rw_blocking) /* Complete read immediately */ { buffer = (uint8 *) xrealloc((void *) buffer, length); if (!buffer) { status = RD_STATUS_CANCELLED; break; } status = fns->read(file, buffer, length, offset, &result); buffer_len = result; break; } /* Add request to table */ pst_buf = (uint8 *) xmalloc(length); if (!pst_buf) { status = RD_STATUS_CANCELLED; break; } serial_get_timeout(file, length, &total_timeout, &interval_timeout); if (add_async_iorequest (device, file, id, major, length, fns, total_timeout, interval_timeout, pst_buf, offset)) { status = RD_STATUS_PENDING; break; } status = RD_STATUS_CANCELLED; break; case IRP_MJ_WRITE: buffer_len = 1; if (!fns->write) { status = RD_STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, length); in_uint32_le(s, offset); in_uint8s(s, 0x18); #if WITH_DEBUG_RDP5 DEBUG(("RDPDR IRP Write (length: %d)\n", result)); #endif if (!rdpdr_handle_ok(device, file)) { status = RD_STATUS_INVALID_HANDLE; break; } if (rw_blocking) /* Complete immediately */ { status = fns->write(file, s->p, length, offset, &result); break; } /* Add to table */ pst_buf = (uint8 *) xmalloc(length); if (!pst_buf) { status = RD_STATUS_CANCELLED; break; } in_uint8a(s, pst_buf, length); if (add_async_iorequest (device, file, id, major, length, fns, 0, 0, pst_buf, offset)) { status = RD_STATUS_PENDING; break; } status = RD_STATUS_CANCELLED; break; case IRP_MJ_QUERY_INFORMATION: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = RD_STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_information(file, info_level, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_SET_INFORMATION: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = RD_STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_set_information(file, info_level, s, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_QUERY_VOLUME_INFORMATION: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = RD_STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_volume_information(file, info_level, &out); result = buffer_len = out.p - out.data; break; case IRP_MJ_DIRECTORY_CONTROL: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = RD_STATUS_INVALID_HANDLE; break; } switch (minor) { case IRP_MN_QUERY_DIRECTORY: in_uint32_le(s, info_level); in_uint8s(s, 1); in_uint32_le(s, length); in_uint8s(s, 0x17); if (length && length < 2 * 255) { rdp_in_unistr(s, length, &filename, &filename_len); if (filename) convert_to_unix_filename(filename); } out.data = out.p = buffer; out.size = sizeof(buffer); status = disk_query_directory(file, info_level, filename, &out); result = buffer_len = out.p - out.data; if (!buffer_len) buffer_len++; free(filename); break; case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* JIF unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */ in_uint32_le(s, info_level); /* notify mask */ status = disk_create_notify(file, info_level); result = 0; if (status == RD_STATUS_PENDING) add_async_iorequest(device, file, id, major, length, fns, 0, 0, NULL, 0); break; default: status = RD_STATUS_INVALID_PARAMETER; /* JIF */ unimpl("IRP major=0x%x minor=0x%x\n", major, minor); } break; case IRP_MJ_DEVICE_CONTROL: if (!fns->device_control) { status = RD_STATUS_NOT_SUPPORTED; break; } in_uint32_le(s, bytes_out); in_uint32_le(s, bytes_in); in_uint32_le(s, request); in_uint8s(s, 0x14); buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14); if (!buffer) { status = RD_STATUS_CANCELLED; break; } out.data = out.p = buffer; out.size = sizeof(buffer); #ifdef WITH_SCARD scardSetInfo(g_epoch, device, id, bytes_out + 0x14); #endif status = fns->device_control(file, request, s, &out); result = buffer_len = out.p - out.data; /* Serial SERIAL_WAIT_ON_MASK */ if (status == RD_STATUS_PENDING) { if (add_async_iorequest (device, file, id, major, length, fns, 0, 0, NULL, 0)) { status = RD_STATUS_PENDING; break; } } #ifdef WITH_SCARD else if (status == (RD_STATUS_PENDING | 0xC0000000)) status = RD_STATUS_PENDING; #endif break; case IRP_MJ_LOCK_CONTROL: if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK) { status = RD_STATUS_INVALID_HANDLE; break; } in_uint32_le(s, info_level); out.data = out.p = buffer; out.size = sizeof(buffer); /* FIXME: Perhaps consider actually *do* something here :-) */ status = RD_STATUS_SUCCESS; result = buffer_len = out.p - out.data; break; default: unimpl("IRP major=0x%x minor=0x%x\n", major, minor); break; } if (status != RD_STATUS_PENDING) { rdpdr_send_completion(device, id, status, result, buffer, buffer_len); } if (buffer) xfree(buffer); buffer = NULL; } static void rdpdr_send_client_capability_response(void) { /* DR_CORE_CAPABILITY_RSP */ STREAM s; s = channel_init(rdpdr_channel, 0x50); out_uint16_le(s, RDPDR_CTYP_CORE); out_uint16_le(s, PAKID_CORE_CLIENT_CAPABILITY); out_uint32_le(s, 5); /* count */ out_uint16_le(s, 1); /* first */ out_uint16_le(s, 0x28); /* length */ out_uint32_le(s, 1); out_uint32_le(s, 2); out_uint16_le(s, 2); out_uint16_le(s, 5); out_uint16_le(s, 1); out_uint16_le(s, 5); out_uint16_le(s, 0xFFFF); out_uint16_le(s, 0); out_uint32_le(s, 0); out_uint32_le(s, 3); out_uint32_le(s, 0); out_uint32_le(s, 0); out_uint16_le(s, 2); /* second */ out_uint16_le(s, 8); /* length */ out_uint32_le(s, 1); out_uint16_le(s, 3); /* third */ out_uint16_le(s, 8); /* length */ out_uint32_le(s, 1); out_uint16_le(s, 4); /* fourth */ out_uint16_le(s, 8); /* length */ out_uint32_le(s, 1); out_uint16_le(s, 5); /* fifth */ out_uint16_le(s, 8); /* length */ out_uint32_le(s, 1); s_mark_end(s); channel_send(s, rdpdr_channel); } static void rdpdr_process(STREAM s) { uint32 handle; uint16 vmin; uint16 component; uint16 pakid; #if WITH_DEBUG_RDP5 printf("--- rdpdr_process ---\n"); hexdump(s->p, s->end - s->p); #endif in_uint16(s, component); in_uint16(s, pakid); if (component == RDPDR_CTYP_CORE) { switch (pakid) { case PAKID_CORE_DEVICE_IOREQUEST: rdpdr_process_irp(s); break; case PAKID_CORE_SERVER_ANNOUNCE: /* DR_CORE_SERVER_ANNOUNCE_REQ */ in_uint8s(s, 2); /* skip versionMajor */ in_uint16_le(s, vmin); /* VersionMinor */ in_uint32_le(s, g_client_id); /* ClientID */ /* The RDP client is responsibility to provide a random client id if server version is < 12 */ if (vmin < 0x000c) g_client_id = 0x815ed39d; /* IP address (use 127.0.0.1) 0x815ed39d */ g_epoch++; rdpdr_send_client_announce_reply(); rdpdr_send_client_name_request(); break; case PAKID_CORE_CLIENTID_CONFIRM: rdpdr_send_client_device_list_announce(); break; case PAKID_CORE_DEVICE_REPLY: in_uint32(s, handle); #if WITH_DEBUG_RDP5 DEBUG(("RDPDR: Server connected to resource %d\n", handle)); #endif break; case PAKID_CORE_SERVER_CAPABILITY: rdpdr_send_client_capability_response(); break; default: unimpl("RDPDR pakid 0x%x of component 0x%x\n", pakid, component); break; } } else if (component == RDPDR_CTYP_PRN) { if (pakid == PAKID_PRN_CACHE_DATA) printercache_process(s); } else unimpl("RDPDR component 0x%x\n", component); } RD_BOOL rdpdr_init() { rdpdr_channel = channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP, rdpdr_process); return (rdpdr_channel != NULL); } /* Add file descriptors of pending io request to select() */ void rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, RD_BOOL * timeout) { uint32 select_timeout = 0; /* Timeout value to be used for select() (in millisecons). */ struct async_iorequest *iorq; char c; iorq = g_iorequest; while (iorq != NULL) { if (iorq->fd != 0) { switch (iorq->major) { case IRP_MJ_READ: /* Is this FD valid? FDs will be invalid when reconnecting. FIXME: Real support for reconnects. */ FD_SET(iorq->fd, rfds); *n = MAX(*n, iorq->fd); /* Check if io request timeout is smaller than current (but not 0). */ if (iorq->timeout && (select_timeout == 0 || iorq->timeout < select_timeout)) { /* Set new timeout */ select_timeout = iorq->timeout; g_min_timeout_fd = iorq->fd; /* Remember fd */ tv->tv_sec = select_timeout / 1000; tv->tv_usec = (select_timeout % 1000) * 1000; *timeout = True; break; } if (iorq->itv_timeout && iorq->partial_len > 0 && (select_timeout == 0 || iorq->itv_timeout < select_timeout)) { /* Set new timeout */ select_timeout = iorq->itv_timeout; g_min_timeout_fd = iorq->fd; /* Remember fd */ tv->tv_sec = select_timeout / 1000; tv->tv_usec = (select_timeout % 1000) * 1000; *timeout = True; break; } break; case IRP_MJ_WRITE: /* FD still valid? See above. */ if ((write(iorq->fd, &c, 0) != 0) && (errno == EBADF)) break; FD_SET(iorq->fd, wfds); *n = MAX(*n, iorq->fd); break; case IRP_MJ_DEVICE_CONTROL: if (select_timeout > 5) select_timeout = 5; /* serial event queue */ break; } } iorq = iorq->next; } } struct async_iorequest * rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq) { if (!iorq) return NULL; if (iorq->buffer) xfree(iorq->buffer); if (prev) { prev->next = iorq->next; xfree(iorq); iorq = prev->next; } else { /* Even if NULL */ g_iorequest = iorq->next; xfree(iorq); iorq = NULL; } return iorq; } /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */ static void _rdpdr_check_fds(fd_set * rfds, fd_set * wfds, RD_BOOL timed_out) { RD_NTSTATUS status; uint32 result = 0; DEVICE_FNS *fns; struct async_iorequest *iorq; struct async_iorequest *prev; uint32 req_size = 0; uint32 buffer_len; struct stream out; uint8 *buffer = NULL; if (timed_out) { /* check serial iv_timeout */ iorq = g_iorequest; prev = NULL; while (iorq != NULL) { if (iorq->fd == g_min_timeout_fd) { if ((iorq->partial_len > 0) && (g_rdpdr_device[iorq->device].device_type == DEVICE_TYPE_SERIAL)) { /* iv_timeout between 2 chars, send partial_len */ /*printf("RDPDR: IVT total %u bytes read of %u\n", iorq->partial_len, iorq->length); */ rdpdr_send_completion(iorq->device, iorq->id, RD_STATUS_SUCCESS, iorq->partial_len, iorq->buffer, iorq->partial_len); iorq = rdpdr_remove_iorequest(prev, iorq); return; } else { break; } } else { break; } prev = iorq; if (iorq) iorq = iorq->next; } rdpdr_abort_io(g_min_timeout_fd, 0, RD_STATUS_TIMEOUT); return; } iorq = g_iorequest; prev = NULL; while (iorq != NULL) { if (iorq->fd != 0) { switch (iorq->major) { case IRP_MJ_READ: if (FD_ISSET(iorq->fd, rfds)) { /* Read the data */ fns = iorq->fns; req_size = (iorq->length - iorq->partial_len) > 8192 ? 8192 : (iorq->length - iorq->partial_len); /* never read larger chunks than 8k - chances are that it will block */ status = fns->read(iorq->fd, iorq->buffer + iorq->partial_len, req_size, iorq->offset, &result); if ((long) result > 0) { iorq->partial_len += result; iorq->offset += result; } #if WITH_DEBUG_RDP5 DEBUG(("RDPDR: %d bytes of data read\n", result)); #endif /* only delete link if all data has been transfered */ /* or if result was 0 and status success - EOF */ if ((iorq->partial_len == iorq->length) || (result == 0)) { #if WITH_DEBUG_RDP5 DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length)); #endif rdpdr_send_completion(iorq->device, iorq->id, status, iorq->partial_len, iorq->buffer, iorq->partial_len); iorq = rdpdr_remove_iorequest(prev, iorq); } } break; case IRP_MJ_WRITE: if (FD_ISSET(iorq->fd, wfds)) { /* Write data. */ fns = iorq->fns; req_size = (iorq->length - iorq->partial_len) > 8192 ? 8192 : (iorq->length - iorq->partial_len); /* never write larger chunks than 8k - chances are that it will block */ status = fns->write(iorq->fd, iorq->buffer + iorq->partial_len, req_size, iorq->offset, &result); if ((long) result > 0) { iorq->partial_len += result; iorq->offset += result; } #if WITH_DEBUG_RDP5 DEBUG(("RDPDR: %d bytes of data written\n", result)); #endif /* only delete link if all data has been transfered */ /* or we couldn't write */ if ((iorq->partial_len == iorq->length) || (result == 0)) { #if WITH_DEBUG_RDP5 DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length)); #endif rdpdr_send_completion(iorq->device, iorq->id, status, iorq->partial_len, (uint8 *) "", 1); iorq = rdpdr_remove_iorequest(prev, iorq); } } break; case IRP_MJ_DEVICE_CONTROL: if (serial_get_event(iorq->fd, &result)) { buffer = (uint8 *) xrealloc((void *) buffer, 0x14); out.data = out.p = buffer; out.size = sizeof(buffer); out_uint32_le(&out, result); result = buffer_len = out.p - out.data; status = RD_STATUS_SUCCESS; rdpdr_send_completion(iorq->device, iorq->id, status, result, buffer, buffer_len); xfree(buffer); iorq = rdpdr_remove_iorequest(prev, iorq); } break; } } prev = iorq; if (iorq) iorq = iorq->next; } /* Check notify */ iorq = g_iorequest; prev = NULL; while (iorq != NULL) { if (iorq->fd != 0) { switch (iorq->major) { case IRP_MJ_DIRECTORY_CONTROL: if (g_rdpdr_device[iorq->device].device_type == DEVICE_TYPE_DISK) { if (g_notify_stamp) { g_notify_stamp = False; status = disk_check_notify(iorq->fd); if (status != RD_STATUS_PENDING) { rdpdr_send_completion(iorq->device, iorq->id, status, 0, NULL, 0); iorq = rdpdr_remove_iorequest(prev, iorq); } } } break; } } prev = iorq; if (iorq) iorq = iorq->next; } } void rdpdr_check_fds(fd_set * rfds, fd_set * wfds, RD_BOOL timed_out) { fd_set dummy; FD_ZERO(&dummy); /* fist check event queue only, any serial wait event must be done before read block will be sent */ _rdpdr_check_fds(&dummy, &dummy, False); _rdpdr_check_fds(rfds, wfds, timed_out); } /* Abort a pending io request for a given handle and major */ RD_BOOL rdpdr_abort_io(uint32 fd, uint32 major, RD_NTSTATUS status) { uint32 result; struct async_iorequest *iorq; struct async_iorequest *prev; iorq = g_iorequest; prev = NULL; while (iorq != NULL) { /* Only remove from table when major is not set, or when correct major is supplied. Abort read should not abort a write io request. */ if ((iorq->fd == fd) && (major == 0 || iorq->major == major)) { result = 0; rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "", 1); iorq = rdpdr_remove_iorequest(prev, iorq); return True; } prev = iorq; iorq = iorq->next; } return False; } rdesktop-1.8.3/rdpsnd_alsa.c0000664000770100510440000002575311551304323014744 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Sound Channel Process Functions - alsa-driver Copyright (C) Matthew Chapman 2003-2008 Copyright (C) GuoJunBo 2003 Copyright (C) Michael Gernoth 2006-2008 Copyright 2006-2008 Pierre Ossman for Cendio AB 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 3 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, see . */ #include "rdesktop.h" #include "rdpsnd.h" #include "rdpsnd_dsp.h" #include #include #include #include #include #define DEFAULTDEVICE "default" #define MAX_FRAMES 32 static struct pollfd pfds_out[32]; static int num_fds_out; static struct pollfd pfds_in[32]; static int num_fds_in; static snd_pcm_t *out_handle = NULL; static snd_pcm_t *in_handle = NULL; static RD_BOOL reopened; static short samplewidth_out; static int audiochannels_out; static unsigned int rate_out; static short samplewidth_in; static int audiochannels_in; static unsigned int rate_in; static char *pcm_name; void alsa_play(void); void alsa_record(void); void alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { int err; struct pollfd *f; if (out_handle && !rdpsnd_queue_empty()) { num_fds_out = snd_pcm_poll_descriptors_count(out_handle); if (num_fds_out > sizeof(pfds_out) / sizeof(*pfds_out)) return; err = snd_pcm_poll_descriptors(out_handle, pfds_out, num_fds_out); if (err < 0) return; for (f = pfds_out; f < &pfds_out[num_fds_out]; f++) { if (f->events & POLLIN) FD_SET(f->fd, rfds); if (f->events & POLLOUT) FD_SET(f->fd, wfds); if (f->fd > *n && (f->events & (POLLIN | POLLOUT))) *n = f->fd; } } if (in_handle) { num_fds_in = snd_pcm_poll_descriptors_count(in_handle); if (num_fds_in > sizeof(pfds_in) / sizeof(*pfds_in)) return; err = snd_pcm_poll_descriptors(in_handle, pfds_in, num_fds_in); if (err < 0) return; for (f = pfds_in; f < &pfds_in[num_fds_in]; f++) { if (f->events & POLLIN) FD_SET(f->fd, rfds); if (f->events & POLLOUT) FD_SET(f->fd, wfds); if (f->fd > *n && (f->events & (POLLIN | POLLOUT))) *n = f->fd; } } } void alsa_check_fds(fd_set * rfds, fd_set * wfds) { struct pollfd *f; int err; unsigned short revents; if (out_handle && !rdpsnd_queue_empty()) { for (f = pfds_out; f < &pfds_out[num_fds_out]; f++) { f->revents = 0; if (f->fd != -1) { /* Fixme: This doesn't properly deal with things like POLLHUP */ if (FD_ISSET(f->fd, rfds)) f->revents |= POLLIN; if (FD_ISSET(f->fd, wfds)) f->revents |= POLLOUT; } } err = snd_pcm_poll_descriptors_revents(out_handle, pfds_out, num_fds_out, &revents); if (err < 0) return; if (revents & POLLOUT) alsa_play(); } if (in_handle) { for (f = pfds_in; f < &pfds_in[num_fds_in]; f++) { f->revents = 0; if (f->fd != -1) { /* Fixme: This doesn't properly deal with things like POLLHUP */ if (FD_ISSET(f->fd, rfds)) f->revents |= POLLIN; if (FD_ISSET(f->fd, wfds)) f->revents |= POLLOUT; } } err = snd_pcm_poll_descriptors_revents(in_handle, pfds_in, num_fds_in, &revents); if (err < 0) return; if (revents & POLLIN) alsa_record(); } } static RD_BOOL alsa_set_format(snd_pcm_t * pcm, RD_WAVEFORMATEX * pwfx) { snd_pcm_hw_params_t *hwparams = NULL; int err; unsigned int buffertime; short samplewidth; int audiochannels; unsigned int rate; samplewidth = pwfx->wBitsPerSample / 8; if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0) { error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0) { error("snd_pcm_hw_params_any: %s\n", snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err)); return False; } if (pwfx->wBitsPerSample == 16) { if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) { error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err)); return False; } } else { if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S8)) < 0) { error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err)); return False; } } #if 0 if ((err = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 1)) < 0) { error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err)); return False; } #endif rate = pwfx->nSamplesPerSec; if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0) { error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err)); return False; } audiochannels = pwfx->nChannels; if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams, pwfx->nChannels)) < 0) { error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err)); return False; } buffertime = 500000; /* microseconds */ if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams, &buffertime, 0)) < 0) { error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0) { error("snd_pcm_hw_params: %s\n", snd_strerror(err)); return False; } snd_pcm_hw_params_free(hwparams); if ((err = snd_pcm_prepare(pcm)) < 0) { error("snd_pcm_prepare: %s\n", snd_strerror(err)); return False; } reopened = True; return True; } RD_BOOL alsa_open_out(void) { int err; if ((err = snd_pcm_open(&out_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { error("snd_pcm_open: %s\n", snd_strerror(err)); return False; } reopened = True; return True; } void alsa_close_out(void) { /* Ack all remaining packets */ while (!rdpsnd_queue_empty()) rdpsnd_queue_next(0); if (out_handle) { snd_pcm_close(out_handle); out_handle = NULL; } } RD_BOOL alsa_format_supported(RD_WAVEFORMATEX * pwfx) { #if 0 int err; snd_pcm_hw_params_t *hwparams = NULL; if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0) { error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err)); return False; } if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) { error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err)); return False; } snd_pcm_hw_params_free(hwparams); #endif if (pwfx->wFormatTag != WAVE_FORMAT_PCM) return False; if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2)) return False; if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16)) return False; if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050)) return False; return True; } RD_BOOL alsa_set_format_out(RD_WAVEFORMATEX * pwfx) { if (!alsa_set_format(out_handle, pwfx)) return False; samplewidth_out = pwfx->wBitsPerSample / 8; audiochannels_out = pwfx->nChannels; rate_out = pwfx->nSamplesPerSec; return True; } void alsa_play(void) { struct audio_packet *packet; STREAM out; int len; static long prev_s, prev_us; unsigned int duration; struct timeval tv; int next_tick; if (reopened) { reopened = False; gettimeofday(&tv, NULL); prev_s = tv.tv_sec; prev_us = tv.tv_usec; } /* We shouldn't be called if the queue is empty, but still */ if (rdpsnd_queue_empty()) return; packet = rdpsnd_queue_current_packet(); out = &packet->s; next_tick = rdpsnd_queue_next_tick(); len = (out->end - out->p) / (samplewidth_out * audiochannels_out); if ((len = snd_pcm_writei(out_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0) { printf("Fooo!\n"); snd_pcm_prepare(out_handle); len = 0; } out->p += (len * samplewidth_out * audiochannels_out); gettimeofday(&tv, NULL); duration = ((tv.tv_sec - prev_s) * 1000000 + (tv.tv_usec - prev_us)) / 1000; if (packet->tick > next_tick) next_tick += 65536; if ((out->p == out->end) || duration > next_tick - packet->tick + 500) { snd_pcm_sframes_t delay_frames; unsigned long delay_us; prev_s = tv.tv_sec; prev_us = tv.tv_usec; if (abs((next_tick - packet->tick) - duration) > 20) { DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick)); DEBUG(("last: %d, is: %d, should: %d\n", packet->tick, (packet->tick + duration) % 65536, next_tick % 65536)); } if (snd_pcm_delay(out_handle, &delay_frames) < 0) delay_frames = out->size / (samplewidth_out * audiochannels_out); if (delay_frames < 0) delay_frames = 0; delay_us = delay_frames * (1000000 / rate_out); rdpsnd_queue_next(delay_us); } } RD_BOOL alsa_open_in(void) { int err; if ((err = snd_pcm_open(&in_handle, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { error("snd_pcm_open: %s\n", snd_strerror(err)); return False; } return True; } void alsa_close_in(void) { if (in_handle) { snd_pcm_close(in_handle); in_handle = NULL; } } RD_BOOL alsa_set_format_in(RD_WAVEFORMATEX * pwfx) { int err; if (!alsa_set_format(in_handle, pwfx)) return False; if ((err = snd_pcm_start(in_handle)) < 0) { error("snd_pcm_start: %s\n", snd_strerror(err)); return False; } samplewidth_in = pwfx->wBitsPerSample / 8; audiochannels_in = pwfx->nChannels; rate_in = pwfx->nSamplesPerSec; return True; } void alsa_record(void) { int len; char buffer[32768]; len = snd_pcm_readi(in_handle, buffer, sizeof(buffer) / (samplewidth_in * audiochannels_in)); if (len < 0) { snd_pcm_prepare(in_handle); len = 0; } rdpsnd_record(buffer, len * samplewidth_in * audiochannels_in); } struct audio_driver * alsa_register(char *options) { static struct audio_driver alsa_driver; memset(&alsa_driver, 0, sizeof(alsa_driver)); alsa_driver.name = "alsa"; alsa_driver.description = "ALSA output driver, default device: " DEFAULTDEVICE; alsa_driver.add_fds = alsa_add_fds; alsa_driver.check_fds = alsa_check_fds; alsa_driver.wave_out_open = alsa_open_out; alsa_driver.wave_out_close = alsa_close_out; alsa_driver.wave_out_format_supported = alsa_format_supported; alsa_driver.wave_out_set_format = alsa_set_format_out; alsa_driver.wave_out_volume = rdpsnd_dsp_softvol_set; alsa_driver.wave_in_open = alsa_open_in; alsa_driver.wave_in_close = alsa_close_in; alsa_driver.wave_in_format_supported = alsa_format_supported; alsa_driver.wave_in_set_format = alsa_set_format_in; alsa_driver.wave_in_volume = NULL; /* FIXME */ alsa_driver.need_byteswap_on_be = 0; alsa_driver.need_resampling = 0; if (options) { pcm_name = xstrdup(options); } else { pcm_name = DEFAULTDEVICE; } return &alsa_driver; } rdesktop-1.8.3/rdpsnd.c0000664000770100510440000005423012334426557013752 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Sound Channel Process Functions Copyright 2006-2010 Pierre Ossman for Cendio AB Copyright 2009-2011 Peter Astrand for Cendio AB Copyright (C) Matthew Chapman 2003-2008 Copyright (C) GuoJunBo 2003 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 3 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, see . */ #include #include "rdesktop.h" #include "rdpsnd.h" #include "rdpsnd_dsp.h" #define RDPSND_CLOSE 1 #define RDPSND_WRITE 2 #define RDPSND_SET_VOLUME 3 #define RDPSND_UNKNOWN4 4 #define RDPSND_COMPLETION 5 #define RDPSND_PING 6 #define RDPSND_NEGOTIATE 7 #define RDPSND_REC_NEGOTIATE 39 #define RDPSND_REC_START 40 #define RDPSND_REC_STOP 41 #define RDPSND_REC_DATA 42 #define RDPSND_REC_SET_VOLUME 43 /* Special flag for RDPSND recording extension, not defined in MS specs. See doc/rdpsnd-rec.txt for more information. */ #define RDPSND_FLAG_RECORD 0x00800000 #define MAX_FORMATS 10 #define MAX_QUEUE 50 extern RD_BOOL g_rdpsnd; static VCHANNEL *rdpsnd_channel; static VCHANNEL *rdpsnddbg_channel; static struct audio_driver *drivers = NULL; struct audio_driver *current_driver = NULL; static RD_BOOL rdpsnd_negotiated; static RD_BOOL rdpsnd_rec_negotiated; static RD_BOOL device_open; static RD_BOOL rec_device_open; static RD_WAVEFORMATEX formats[MAX_FORMATS]; static unsigned int format_count; static unsigned int current_format; static RD_WAVEFORMATEX rec_formats[MAX_FORMATS]; static unsigned int rec_format_count; static unsigned int rec_current_format; unsigned int queue_hi, queue_lo, queue_pending; struct audio_packet packet_queue[MAX_QUEUE]; static char record_buffer[8192]; static uint32 record_buffer_size; static uint8 packet_opcode; static struct stream packet; void (*wave_out_play) (void); static void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index); static void rdpsnd_queue_init(void); static void rdpsnd_queue_clear(void); static void rdpsnd_queue_complete_pending(void); static long rdpsnd_queue_next_completion(void); static STREAM rdpsnd_init_packet(uint16 type, uint16 size) { STREAM s; s = channel_init(rdpsnd_channel, size + 4); out_uint16_le(s, type); out_uint16_le(s, size); return s; } static void rdpsnd_send(STREAM s) { channel_send(s, rdpsnd_channel); } static void rdpsnd_send_completion(uint16 tick, uint8 packet_index) { STREAM s; s = rdpsnd_init_packet(RDPSND_COMPLETION, 4); out_uint16_le(s, tick); out_uint8(s, packet_index); out_uint8(s, 0); s_mark_end(s); rdpsnd_send(s); DEBUG_SOUND(("RDPSND: -> RDPSND_COMPLETION(tick: %u, index: %u)\n", (unsigned) tick, (unsigned) packet_index)); } static void rdpsnd_flush_record(void) { STREAM s; unsigned int chunk_size; char *data; if (record_buffer_size == 0) return; assert(record_buffer_size <= sizeof(record_buffer)); data = record_buffer; /* * Microsoft's RDP server keeps dropping chunks, so we need to * transmit everything inside one channel fragment or we risk * making the rdpsnd server go out of sync with the byte stream. */ while (record_buffer_size) { if (record_buffer_size < 1596) chunk_size = record_buffer_size; else chunk_size = 1596; s = rdpsnd_init_packet(RDPSND_REC_DATA, chunk_size); out_uint8p(s, data, chunk_size); s_mark_end(s); rdpsnd_send(s); data = data + chunk_size; record_buffer_size -= chunk_size; DEBUG_SOUND(("RDPSND: -> RDPSND_REC_DATA(length: %u)\n", (unsigned) chunk_size)); } record_buffer_size = 0; } static void rdpsnd_clear_record(void) { /* * Silently drop everything we have in the record buffer as * we've somehow gotten a reset in regard to the server. */ record_buffer_size = 0; } void rdpsnd_record(const void *data, unsigned int size) { uint32 remain, chunk; assert(rec_device_open); while (size) { remain = sizeof(record_buffer) - record_buffer_size; if (size >= remain) chunk = remain; else chunk = size; memcpy(record_buffer + record_buffer_size, data, chunk); #ifdef B_ENDIAN if (current_driver->need_byteswap_on_be) rdpsnd_dsp_swapbytes(record_buffer + record_buffer_size, chunk, &rec_formats[rec_current_format]); #endif record_buffer_size += chunk; data = (const char *) data + chunk; size -= chunk; if (record_buffer_size == sizeof(record_buffer)) rdpsnd_flush_record(); } } static RD_BOOL rdpsnd_auto_select(void) { static RD_BOOL failed = False; if (!failed) { current_driver = drivers; while (current_driver != NULL) { DEBUG(("trying %s...\n", current_driver->name)); if (current_driver->wave_out_open()) { DEBUG(("selected %s\n", current_driver->name)); current_driver->wave_out_close(); return True; } current_driver = current_driver->next; } warning("no working audio-driver found\n"); failed = True; current_driver = NULL; } return False; } static void rdpsnd_process_negotiate(STREAM in) { uint16 in_format_count, i; uint8 pad; uint16 version; RD_WAVEFORMATEX *format; STREAM out; RD_BOOL device_available = False; int readcnt; int discardcnt; in_uint8s(in, 14); /* initial bytes not valid from server */ in_uint16_le(in, in_format_count); in_uint8(in, pad); in_uint16_le(in, version); in_uint8s(in, 1); /* padding */ DEBUG_SOUND(("RDPSND: RDPSND_NEGOTIATE(formats: %d, pad: 0x%02x, version: %x)\n", (int) in_format_count, (unsigned) pad, (unsigned) version)); if (rdpsnd_negotiated) { error("RDPSND: Extra RDPSND_NEGOTIATE in the middle of a session\n"); /* Do a complete reset of the sound state */ rdpsnd_reset_state(); } if (!current_driver && g_rdpsnd) device_available = rdpsnd_auto_select(); if (current_driver && !device_available && current_driver->wave_out_open()) { current_driver->wave_out_close(); device_available = True; } format_count = 0; if (s_check_rem(in, 18 * in_format_count)) { for (i = 0; i < in_format_count; i++) { format = &formats[format_count]; in_uint16_le(in, format->wFormatTag); in_uint16_le(in, format->nChannels); in_uint32_le(in, format->nSamplesPerSec); in_uint32_le(in, format->nAvgBytesPerSec); in_uint16_le(in, format->nBlockAlign); in_uint16_le(in, format->wBitsPerSample); in_uint16_le(in, format->cbSize); /* read in the buffer of unknown use */ readcnt = format->cbSize; discardcnt = 0; if (format->cbSize > MAX_CBSIZE) { fprintf(stderr, "cbSize too large for buffer: %d\n", format->cbSize); readcnt = MAX_CBSIZE; discardcnt = format->cbSize - MAX_CBSIZE; } in_uint8a(in, format->cb, readcnt); in_uint8s(in, discardcnt); if (current_driver && current_driver->wave_out_format_supported(format)) { format_count++; if (format_count == MAX_FORMATS) break; } } } out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count); uint32 flags = TSSNDCAPS_VOLUME; /* if sound is enabled, set snd caps to alive to enable transmision of audio from server */ if (g_rdpsnd) { flags |= TSSNDCAPS_ALIVE; flags |= RDPSND_FLAG_RECORD; } out_uint32_le(out, flags); /* TSSNDCAPS flags */ out_uint32(out, 0xffffffff); /* volume */ out_uint32(out, 0); /* pitch */ out_uint16(out, 0); /* UDP port */ out_uint16_le(out, format_count); out_uint8(out, 0); /* padding */ out_uint16_le(out, 2); /* version */ out_uint8(out, 0); /* padding */ for (i = 0; i < format_count; i++) { format = &formats[i]; out_uint16_le(out, format->wFormatTag); out_uint16_le(out, format->nChannels); out_uint32_le(out, format->nSamplesPerSec); out_uint32_le(out, format->nAvgBytesPerSec); out_uint16_le(out, format->nBlockAlign); out_uint16_le(out, format->wBitsPerSample); out_uint16(out, 0); /* cbSize */ } s_mark_end(out); DEBUG_SOUND(("RDPSND: -> RDPSND_NEGOTIATE(formats: %d)\n", (int) format_count)); rdpsnd_send(out); rdpsnd_negotiated = True; } static void rdpsnd_process_ping(STREAM in) { uint16 tick; STREAM out; in_uint16_le(in, tick); DEBUG_SOUND(("RDPSND: RDPSND_PING(tick: 0x%04x)\n", (unsigned) tick)); out = rdpsnd_init_packet(RDPSND_PING | 0x2300, 4); out_uint16_le(out, tick); out_uint16_le(out, 0); s_mark_end(out); rdpsnd_send(out); DEBUG_SOUND(("RDPSND: -> (tick: 0x%04x)\n", (unsigned) tick)); } static void rdpsnd_process_rec_negotiate(STREAM in) { uint16 in_format_count, i; uint16 version; RD_WAVEFORMATEX *format; STREAM out; RD_BOOL device_available = False; int readcnt; int discardcnt; in_uint8s(in, 8); /* initial bytes not valid from server */ in_uint16_le(in, in_format_count); in_uint16_le(in, version); DEBUG_SOUND(("RDPSND: RDPSND_REC_NEGOTIATE(formats: %d, version: %x)\n", (int) in_format_count, (unsigned) version)); if (rdpsnd_rec_negotiated) { error("RDPSND: Extra RDPSND_REC_NEGOTIATE in the middle of a session\n"); /* Do a complete reset of the sound state */ rdpsnd_reset_state(); } if (!current_driver) device_available = rdpsnd_auto_select(); if (current_driver && !device_available && current_driver->wave_in_open && current_driver->wave_in_open()) { current_driver->wave_in_close(); device_available = True; } rec_format_count = 0; if (s_check_rem(in, 18 * in_format_count)) { for (i = 0; i < in_format_count; i++) { format = &rec_formats[rec_format_count]; in_uint16_le(in, format->wFormatTag); in_uint16_le(in, format->nChannels); in_uint32_le(in, format->nSamplesPerSec); in_uint32_le(in, format->nAvgBytesPerSec); in_uint16_le(in, format->nBlockAlign); in_uint16_le(in, format->wBitsPerSample); in_uint16_le(in, format->cbSize); /* read in the buffer of unknown use */ readcnt = format->cbSize; discardcnt = 0; if (format->cbSize > MAX_CBSIZE) { fprintf(stderr, "cbSize too large for buffer: %d\n", format->cbSize); readcnt = MAX_CBSIZE; discardcnt = format->cbSize - MAX_CBSIZE; } in_uint8a(in, format->cb, readcnt); in_uint8s(in, discardcnt); if (current_driver && current_driver->wave_in_format_supported && current_driver->wave_in_format_supported(format)) { rec_format_count++; if (rec_format_count == MAX_FORMATS) break; } } } out = rdpsnd_init_packet(RDPSND_REC_NEGOTIATE, 12 + 18 * rec_format_count); out_uint32_le(out, 0x00000000); /* flags */ out_uint32_le(out, 0xffffffff); /* volume */ out_uint16_le(out, rec_format_count); out_uint16_le(out, 1); /* version */ for (i = 0; i < rec_format_count; i++) { format = &rec_formats[i]; out_uint16_le(out, format->wFormatTag); out_uint16_le(out, format->nChannels); out_uint32_le(out, format->nSamplesPerSec); out_uint32_le(out, format->nAvgBytesPerSec); out_uint16_le(out, format->nBlockAlign); out_uint16_le(out, format->wBitsPerSample); out_uint16(out, 0); /* cbSize */ } s_mark_end(out); DEBUG_SOUND(("RDPSND: -> RDPSND_REC_NEGOTIATE(formats: %d)\n", (int) rec_format_count)); rdpsnd_send(out); rdpsnd_rec_negotiated = True; } static void rdpsnd_process_packet(uint8 opcode, STREAM s) { uint16 vol_left, vol_right; static uint16 tick, format; static uint8 packet_index; switch (opcode) { case RDPSND_WRITE: in_uint16_le(s, tick); in_uint16_le(s, format); in_uint8(s, packet_index); in_uint8s(s, 3); DEBUG_SOUND(("RDPSND: RDPSND_WRITE(tick: %u, format: %u, index: %u, data: %u bytes)\n", (unsigned) tick, (unsigned) format, (unsigned) packet_index, (unsigned) s->size - 8)); if (format >= MAX_FORMATS) { error("RDPSND: Invalid format index\n"); break; } if (!device_open || (format != current_format)) { /* * If we haven't selected a device by now, then either * we've failed to find a working device, or the server * is sending bogus RDPSND_WRITE. */ if (!current_driver) { rdpsnd_send_completion(tick, packet_index); break; } if (!device_open && !current_driver->wave_out_open()) { rdpsnd_send_completion(tick, packet_index); break; } if (!current_driver->wave_out_set_format(&formats[format])) { rdpsnd_send_completion(tick, packet_index); current_driver->wave_out_close(); device_open = False; break; } device_open = True; current_format = format; } rdpsnd_queue_write(rdpsnd_dsp_process (s->p, s->end - s->p, current_driver, &formats[current_format]), tick, packet_index); return; break; case RDPSND_CLOSE: DEBUG_SOUND(("RDPSND: RDPSND_CLOSE()\n")); if (device_open) current_driver->wave_out_close(); device_open = False; break; case RDPSND_NEGOTIATE: rdpsnd_process_negotiate(s); break; case RDPSND_PING: rdpsnd_process_ping(s); break; case RDPSND_SET_VOLUME: in_uint16_le(s, vol_left); in_uint16_le(s, vol_right); DEBUG_SOUND(("RDPSND: RDPSND_VOLUME(left: 0x%04x (%u %%), right: 0x%04x (%u %%))\n", (unsigned) vol_left, (unsigned) vol_left / 655, (unsigned) vol_right, (unsigned) vol_right / 655)); if (device_open) current_driver->wave_out_volume(vol_left, vol_right); break; case RDPSND_REC_NEGOTIATE: rdpsnd_process_rec_negotiate(s); break; case RDPSND_REC_START: in_uint16_le(s, format); DEBUG_SOUND(("RDPSND: RDPSND_REC_START(format: %u)\n", (unsigned) format)); if (format >= MAX_FORMATS) { error("RDPSND: Invalid format index\n"); break; } if (rec_device_open) { error("RDPSND: Multiple RDPSND_REC_START\n"); break; } if (!current_driver->wave_in_open()) break; if (!current_driver->wave_in_set_format(&rec_formats[format])) { error("RDPSND: Device not accepting format\n"); current_driver->wave_in_close(); break; } rec_current_format = format; rec_device_open = True; break; case RDPSND_REC_STOP: DEBUG_SOUND(("RDPSND: RDPSND_REC_STOP()\n")); rdpsnd_flush_record(); if (rec_device_open) current_driver->wave_in_close(); rec_device_open = False; break; case RDPSND_REC_SET_VOLUME: in_uint16_le(s, vol_left); in_uint16_le(s, vol_right); DEBUG_SOUND(("RDPSND: RDPSND_REC_VOLUME(left: 0x%04x (%u %%), right: 0x%04x (%u %%))\n", (unsigned) vol_left, (unsigned) vol_left / 655, (unsigned) vol_right, (unsigned) vol_right / 655)); if (rec_device_open) current_driver->wave_in_volume(vol_left, vol_right); break; default: unimpl("RDPSND packet type %x\n", opcode); break; } } static void rdpsnd_process(STREAM s) { uint16 len; while (!s_check_end(s)) { /* New packet */ if (packet.size == 0) { if ((s->end - s->p) < 4) { error("RDPSND: Split at packet header. Things will go south from here...\n"); return; } in_uint8(s, packet_opcode); in_uint8s(s, 1); /* Padding */ in_uint16_le(s, len); DEBUG_SOUND(("RDPSND: == Opcode %x Length: %d ==\n", (int) packet_opcode, (int) len)); packet.p = packet.data; packet.end = packet.data + len; packet.size = len; } else { len = MIN(s->end - s->p, packet.end - packet.p); /* Microsoft's server is so broken it's not even funny... */ if (packet_opcode == RDPSND_WRITE) { if ((packet.p - packet.data) < 12) len = MIN(len, 12 - (packet.p - packet.data)); else if ((packet.p - packet.data) == 12) { DEBUG_SOUND(("RDPSND: Eating 4 bytes of %d bytes...\n", len)); in_uint8s(s, 4); len -= 4; } } in_uint8a(s, packet.p, len); packet.p += len; } /* Packet fully assembled */ if (packet.p == packet.end) { packet.p = packet.data; rdpsnd_process_packet(packet_opcode, &packet); packet.size = 0; } } } static RD_BOOL rdpsnddbg_line_handler(const char *line, void *data) { #ifdef WITH_DEBUG_SOUND fprintf(stderr, "SNDDBG: %s\n", line); #endif return True; } static void rdpsnddbg_process(STREAM s) { unsigned int pkglen; static char *rest = NULL; char *buf; pkglen = s->end - s->p; /* str_handle_lines requires null terminated strings */ buf = (char *) xmalloc(pkglen + 1); STRNCPY(buf, (char *) s->p, pkglen + 1); str_handle_lines(buf, &rest, rdpsnddbg_line_handler, NULL); xfree(buf); } static void rdpsnd_register_drivers(char *options) { struct audio_driver **reg; /* The order of registrations define the probe-order when opening the device for the first time */ reg = &drivers; #if defined(RDPSND_ALSA) *reg = alsa_register(options); assert(*reg); reg = &((*reg)->next); #endif #if defined(RDPSND_SUN) *reg = sun_register(options); assert(*reg); reg = &((*reg)->next); #endif #if defined(RDPSND_OSS) *reg = oss_register(options); assert(*reg); reg = &((*reg)->next); #endif #if defined(RDPSND_SGI) *reg = sgi_register(options); assert(*reg); reg = &((*reg)->next); #endif #if defined(RDPSND_LIBAO) *reg = libao_register(options); assert(*reg); reg = &((*reg)->next); #endif *reg = NULL; } RD_BOOL rdpsnd_init(char *optarg) { struct audio_driver *pos; char *driver = NULL, *options = NULL; drivers = NULL; packet.data = (uint8 *) xmalloc(65536); packet.p = packet.end = packet.data; packet.size = 0; rdpsnd_channel = channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, rdpsnd_process); rdpsnddbg_channel = channel_register("snddbg", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, rdpsnddbg_process); if ((rdpsnd_channel == NULL) || (rdpsnddbg_channel == NULL)) { error("channel_register\n"); return False; } rdpsnd_queue_init(); if (optarg != NULL && strlen(optarg) > 0) { driver = options = optarg; while (*options != '\0' && *options != ':') options++; if (*options == ':') { *options = '\0'; options++; } if (*options == '\0') options = NULL; } rdpsnd_register_drivers(options); if (!driver) return True; pos = drivers; while (pos != NULL) { if (!strcmp(pos->name, driver)) { DEBUG(("selected %s\n", pos->name)); current_driver = pos; return True; } pos = pos->next; } return False; } void rdpsnd_reset_state(void) { if (device_open) current_driver->wave_out_close(); device_open = False; rdpsnd_queue_clear(); rdpsnd_negotiated = False; if (rec_device_open) current_driver->wave_in_close(); rec_device_open = False; rdpsnd_clear_record(); rdpsnd_rec_negotiated = False; } void rdpsnd_show_help(void) { struct audio_driver *pos; rdpsnd_register_drivers(NULL); pos = drivers; while (pos != NULL) { fprintf(stderr, " %s:\t%s\n", pos->name, pos->description); pos = pos->next; } } void rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { long next_pending; if (device_open || rec_device_open) current_driver->add_fds(n, rfds, wfds, tv); next_pending = rdpsnd_queue_next_completion(); if (next_pending >= 0) { long cur_timeout; cur_timeout = tv->tv_sec * 1000000 + tv->tv_usec; if (cur_timeout > next_pending) { tv->tv_sec = next_pending / 1000000; tv->tv_usec = next_pending % 1000000; } } } void rdpsnd_check_fds(fd_set * rfds, fd_set * wfds) { rdpsnd_queue_complete_pending(); if (device_open || rec_device_open) current_driver->check_fds(rfds, wfds); } static void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index) { struct audio_packet *packet = &packet_queue[queue_hi]; unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE; if (next_hi == queue_pending) { error("No space to queue audio packet\n"); return; } queue_hi = next_hi; packet->s = *s; packet->tick = tick; packet->index = index; gettimeofday(&packet->arrive_tv, NULL); } struct audio_packet * rdpsnd_queue_current_packet(void) { return &packet_queue[queue_lo]; } RD_BOOL rdpsnd_queue_empty(void) { return (queue_lo == queue_hi); } static void rdpsnd_queue_init(void) { queue_pending = queue_lo = queue_hi = 0; } static void rdpsnd_queue_clear(void) { struct audio_packet *packet; /* Go through everything, not just the pending packets */ while (queue_pending != queue_hi) { packet = &packet_queue[queue_pending]; xfree(packet->s.data); queue_pending = (queue_pending + 1) % MAX_QUEUE; } /* Reset everything back to the initial state */ queue_pending = queue_lo = queue_hi = 0; } void rdpsnd_queue_next(unsigned long completed_in_us) { struct audio_packet *packet; assert(!rdpsnd_queue_empty()); packet = &packet_queue[queue_lo]; gettimeofday(&packet->completion_tv, NULL); packet->completion_tv.tv_usec += completed_in_us; packet->completion_tv.tv_sec += packet->completion_tv.tv_usec / 1000000; packet->completion_tv.tv_usec %= 1000000; queue_lo = (queue_lo + 1) % MAX_QUEUE; rdpsnd_queue_complete_pending(); } int rdpsnd_queue_next_tick(void) { if (((queue_lo + 1) % MAX_QUEUE) != queue_hi) { return packet_queue[(queue_lo + 1) % MAX_QUEUE].tick; } else { return (packet_queue[queue_lo].tick + 65535) % 65536; } } static void rdpsnd_queue_complete_pending(void) { struct timeval now; long elapsed; struct audio_packet *packet; gettimeofday(&now, NULL); while (queue_pending != queue_lo) { packet = &packet_queue[queue_pending]; if (now.tv_sec < packet->completion_tv.tv_sec) break; if ((now.tv_sec == packet->completion_tv.tv_sec) && (now.tv_usec < packet->completion_tv.tv_usec)) break; elapsed = (packet->completion_tv.tv_sec - packet->arrive_tv.tv_sec) * 1000000 + (packet->completion_tv.tv_usec - packet->arrive_tv.tv_usec); elapsed /= 1000; xfree(packet->s.data); rdpsnd_send_completion((packet->tick + elapsed) % 65536, packet->index); queue_pending = (queue_pending + 1) % MAX_QUEUE; } } static long rdpsnd_queue_next_completion(void) { struct audio_packet *packet; long remaining; struct timeval now; if (queue_pending == queue_lo) return -1; gettimeofday(&now, NULL); packet = &packet_queue[queue_pending]; remaining = (packet->completion_tv.tv_sec - now.tv_sec) * 1000000 + (packet->completion_tv.tv_usec - now.tv_usec); if (remaining < 0) return 0; return remaining; } rdesktop-1.8.3/rdpsnd_dsp.c0000664000770100510440000002456112215576544014624 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Sound DSP routines Copyright (C) Michael Gernoth 2006-2008 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 3 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, see . */ #include #include "rdesktop.h" #include "rdpsnd.h" #include "rdpsnd_dsp.h" #ifdef HAVE_LIBSAMPLERATE #include #define SRC_CONVERTER SRC_SINC_MEDIUM_QUALITY #endif #define MAX_VOLUME 65535 static uint16 softvol_left = MAX_VOLUME; static uint16 softvol_right = MAX_VOLUME; static uint32 resample_to_srate = 44100; static uint16 resample_to_bitspersample = 16; static uint16 resample_to_channels = 2; #ifdef HAVE_LIBSAMPLERATE static SRC_STATE *src_converter = NULL; #endif void rdpsnd_dsp_softvol_set(uint16 left, uint16 right) { softvol_left = left; softvol_right = right; DEBUG(("rdpsnd_dsp_softvol_set: left: %u, right: %u\n", left, right)); } void rdpsnd_dsp_softvol(unsigned char *buffer, unsigned int size, RD_WAVEFORMATEX * format) { unsigned int factor_left, factor_right; unsigned char *posin = buffer; unsigned char *posout = buffer; if ((softvol_left == MAX_VOLUME) && (softvol_right == MAX_VOLUME)) return; factor_left = (softvol_left * 256) / MAX_VOLUME; factor_right = (softvol_right * 256) / MAX_VOLUME; if (format->nChannels == 1) { factor_left = factor_right = (factor_left + factor_right) / 2; } if (format->wBitsPerSample == 8) { sint8 val; while (posout < buffer + size) { /* Left */ val = *posin++; val = (val * factor_left) >> 8; *posout++ = val; /* Right */ val = *posin++; val = (val * factor_right) >> 8; *posout++ = val; } } else { sint16 val; while (posout < buffer + size) { /* Left */ val = *posin++; val |= *posin++ << 8; val = (val * factor_left) >> 8; *posout++ = val & 0xff; *posout++ = val >> 8; /* Right */ val = *posin++; val |= *posin++ << 8; val = (val * factor_right) >> 8; *posout++ = val & 0xff; *posout++ = val >> 8; } } DEBUG(("using softvol with factors left: %d, right: %d (%d/%d)\n", factor_left, factor_right, format->wBitsPerSample, format->nChannels)); } void rdpsnd_dsp_swapbytes(unsigned char *buffer, unsigned int size, RD_WAVEFORMATEX * format) { int i; uint8 swap; if (format->wBitsPerSample == 8) return; if (size & 0x1) warning("badly aligned sound data"); for (i = 0; i < (int) size; i += 2) { swap = *(buffer + i); *(buffer + i) = *(buffer + i + 1); *(buffer + i + 1) = swap; } } RD_BOOL rdpsnd_dsp_resample_set(uint32 device_srate, uint16 device_bitspersample, uint16 device_channels) { #ifdef HAVE_LIBSAMPLERATE int err; #endif if (device_bitspersample != 16 && device_bitspersample != 8) return False; if (device_channels != 1 && device_channels != 2) return False; resample_to_srate = device_srate; resample_to_bitspersample = device_bitspersample; resample_to_channels = device_channels; #ifdef HAVE_LIBSAMPLERATE if (src_converter != NULL) src_converter = src_delete(src_converter); if ((src_converter = src_new(SRC_CONVERTER, device_channels, &err)) == NULL) { warning("src_new failed: %d!\n", err); return False; } #endif return True; } RD_BOOL rdpsnd_dsp_resample_supported(RD_WAVEFORMATEX * format) { if (format->wFormatTag != WAVE_FORMAT_PCM) return False; if ((format->nChannels != 1) && (format->nChannels != 2)) return False; if ((format->wBitsPerSample != 8) && (format->wBitsPerSample != 16)) return False; return True; } uint32 rdpsnd_dsp_resample(unsigned char **out, unsigned char *in, unsigned int size, RD_WAVEFORMATEX * format, RD_BOOL stream_be) { #ifdef HAVE_LIBSAMPLERATE SRC_DATA resample_data; float *infloat, *outfloat; int err; #else int ratio1k = (resample_to_srate * 1000) / format->nSamplesPerSec; #endif int innum, outnum; unsigned char *tmpdata = NULL, *tmp = NULL; int samplewidth = format->wBitsPerSample / 8; int outsize = 0; int i; if ((resample_to_bitspersample == format->wBitsPerSample) && (resample_to_channels == format->nChannels) && (resample_to_srate == format->nSamplesPerSec)) return 0; #ifdef B_ENDIAN if (!stream_be) rdpsnd_dsp_swapbytes(in, size, format); #endif if (resample_to_channels != format->nChannels) { int newsize = (size / format->nChannels) * resample_to_channels; tmpdata = (unsigned char *) xmalloc(newsize); for (i = 0; i < newsize / samplewidth; i++) { if (format->nChannels > resample_to_channels) memcpy(tmpdata + (i * samplewidth), in + (((i * format->nChannels) / resample_to_channels) * samplewidth), samplewidth); else memcpy(tmpdata + (i * samplewidth), in + (((i / resample_to_channels) * format->nChannels + (i % format->nChannels)) * samplewidth), samplewidth); } in = tmpdata; size = newsize; } /* Expand 8bit input-samples to 16bit */ #ifndef HAVE_LIBSAMPLERATE /* libsamplerate needs 16bit samples */ if (format->wBitsPerSample != resample_to_bitspersample) #endif { /* source: 8 bit, dest: 16bit */ if (format->wBitsPerSample == 8) { tmp = tmpdata; tmpdata = (unsigned char *) xmalloc(size * 2); for (i = 0; i < (int) size; i++) { tmpdata[i * 2] = in[i]; tmpdata[(i * 2) + 1] = 0x00; } in = tmpdata; samplewidth = 16 / 2; size *= 2; if (tmp != NULL) xfree(tmp); } } innum = size / samplewidth; /* Do the resampling */ #ifdef HAVE_LIBSAMPLERATE if (src_converter == NULL) { warning("no samplerate converter available!\n"); return 0; } outnum = ((float) innum * ((float) resample_to_srate / (float) format->nSamplesPerSec)) + 1; infloat = (float *) xmalloc(sizeof(float) * innum); outfloat = (float *) xmalloc(sizeof(float) * outnum); src_short_to_float_array((short *) in, infloat, innum); bzero(&resample_data, sizeof(resample_data)); resample_data.data_in = infloat; resample_data.data_out = outfloat; resample_data.input_frames = innum / resample_to_channels; resample_data.output_frames = outnum / resample_to_channels; resample_data.src_ratio = (double) resample_to_srate / (double) format->nSamplesPerSec; resample_data.end_of_input = 0; if ((err = src_process(src_converter, &resample_data)) != 0) error("src_process: %s", src_strerror(err)); xfree(infloat); outsize = resample_data.output_frames_gen * resample_to_channels * samplewidth; *out = (unsigned char *) xmalloc(outsize); src_float_to_short_array(outfloat, (short *) *out, resample_data.output_frames_gen * resample_to_channels); xfree(outfloat); #else /* Michaels simple linear resampler */ if (resample_to_srate < format->nSamplesPerSec) { warning("downsampling currently not supported!\n"); return 0; } outnum = (innum * ratio1k) / 1000; outsize = outnum * samplewidth; *out = (unsigned char *) xmalloc(outsize); bzero(*out, outsize); for (i = 0; i < outsize / (resample_to_channels * samplewidth); i++) { int source = (i * 1000) / ratio1k; #if 0 /* Partial for linear resampler */ int part = (i * 100000) / ratio1k - source * 100; #endif int j; if (source * resample_to_channels + samplewidth > (int) size) break; #if 0 /* Linear resampling, TODO: soundquality fixes (LP filter) */ if (samplewidth == 1) { sint8 cval1, cval2; for (j = 0; j < resample_to_channels; j++) { memcpy(&cval1, in + (source * resample_to_channels * samplewidth) + (samplewidth * j), samplewidth); memcpy(&cval2, in + ((source + 1) * resample_to_channels * samplewidth) + (samplewidth * j), samplewidth); cval1 += (sint8) (cval2 * part) / 100; memcpy(*out + (i * resample_to_channels * samplewidth) + (samplewidth * j), &cval1, samplewidth); } } else { sint16 sval1, sval2; for (j = 0; j < resample_to_channels; j++) { memcpy(&sval1, in + (source * resample_to_channels * samplewidth) + (samplewidth * j), samplewidth); memcpy(&sval2, in + ((source + 1) * resample_to_channels * samplewidth) + (samplewidth * j), samplewidth); sval1 += (sint16) (sval2 * part) / 100; memcpy(*out + (i * resample_to_channels * samplewidth) + (samplewidth * j), &sval1, samplewidth); } } #else /* Nearest neighbor search */ for (j = 0; j < resample_to_channels; j++) { memcpy(*out + (i * resample_to_channels * samplewidth) + (samplewidth * j), in + (source * resample_to_channels * samplewidth) + (samplewidth * j), samplewidth); } #endif } outsize = i * resample_to_channels * samplewidth; #endif if (tmpdata != NULL) xfree(tmpdata); /* Shrink 16bit output-samples to 8bit */ #ifndef HAVE_LIBSAMPLERATE /* libsamplerate produces 16bit samples */ if (format->wBitsPerSample != resample_to_bitspersample) #endif { /* source: 16 bit, dest: 8 bit */ if (resample_to_bitspersample == 8) { for (i = 0; i < outsize; i++) { *out[i] = *out[i * 2]; } outsize /= 2; } } #ifdef B_ENDIAN if (!stream_be) rdpsnd_dsp_swapbytes(*out, outsize, format); #endif return outsize; } STREAM rdpsnd_dsp_process(unsigned char *data, unsigned int size, struct audio_driver * current_driver, RD_WAVEFORMATEX * format) { static struct stream out; RD_BOOL stream_be = False; /* softvol and byteswap do not change the amount of data they return, so they can operate on the input-stream */ if (current_driver->wave_out_volume == rdpsnd_dsp_softvol_set) rdpsnd_dsp_softvol(data, size, format); #ifdef B_ENDIAN if (current_driver->need_byteswap_on_be) { rdpsnd_dsp_swapbytes(data, size, format); stream_be = True; } #endif out.data = NULL; if (current_driver->need_resampling) out.size = rdpsnd_dsp_resample(&out.data, data, size, format, stream_be); if (out.data == NULL) { out.data = (unsigned char *) xmalloc(size); memcpy(out.data, data, size); out.size = size; } out.p = out.data; out.end = out.p + out.size; return &out; } rdesktop-1.8.3/rdpsnd_libao.c0000664000770100510440000001151012202677224015103 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Sound Channel Process Functions - libao-driver Copyright (C) Matthew Chapman 2003-2008 Copyright (C) GuoJunBo 2003 Copyright (C) Michael Gernoth 2005-2008 Copyright (C) 2013 Henrik Andersson 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 3 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, see . */ #include "rdesktop.h" #include "rdpsnd.h" #include "rdpsnd_dsp.h" #include #include #include #include #include #define WAVEOUTLEN 16 static ao_device *o_device = NULL; static int default_driver; static RD_BOOL reopened; static char *libao_device = NULL; void libao_play(void); void libao_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { /* We need to be called rather often... */ if (o_device != NULL && !rdpsnd_queue_empty()) FD_SET(0, wfds); } void libao_check_fds(fd_set * rfds, fd_set * wfds) { if (o_device == NULL) return; if (!rdpsnd_queue_empty()) libao_play(); } RD_BOOL libao_open(void) { ao_sample_format format; ao_initialize(); if (libao_device) { default_driver = ao_driver_id(libao_device); } else { default_driver = ao_default_driver_id(); } memset(&format, 0, sizeof(format)); format.bits = 16; format.channels = 2; format.rate = 44100; format.byte_format = AO_FMT_NATIVE; o_device = ao_open_live(default_driver, &format, NULL); if (o_device == NULL) { return False; } reopened = True; return True; } void libao_close(void) { /* Ack all remaining packets */ while (!rdpsnd_queue_empty()) { rdpsnd_queue_next(0); } if (o_device != NULL) ao_close(o_device); o_device = NULL; ao_shutdown(); } RD_BOOL libao_set_format(RD_WAVEFORMATEX * pwfx) { ao_sample_format format; memset(&format, 0, sizeof(format)); format.bits = pwfx->wBitsPerSample; format.channels = pwfx->nChannels; format.rate = 44100; format.byte_format = AO_FMT_NATIVE; if (o_device != NULL) ao_close(o_device); o_device = ao_open_live(default_driver, &format, NULL); if (o_device == NULL) { return False; } if (rdpsnd_dsp_resample_set(44100, pwfx->wBitsPerSample, pwfx->nChannels) == False) { return False; } reopened = True; return True; } void libao_play(void) { struct audio_packet *packet; STREAM out; int len; static long prev_s, prev_us; unsigned int duration; struct timeval tv; int next_tick; if (reopened) { reopened = False; gettimeofday(&tv, NULL); prev_s = tv.tv_sec; prev_us = tv.tv_usec; } /* We shouldn't be called if the queue is empty, but still */ if (rdpsnd_queue_empty()) return; packet = rdpsnd_queue_current_packet(); out = &packet->s; next_tick = rdpsnd_queue_next_tick(); len = (WAVEOUTLEN > (out->end - out->p)) ? (out->end - out->p) : WAVEOUTLEN; ao_play(o_device, (char *) out->p, len); out->p += len; gettimeofday(&tv, NULL); duration = ((tv.tv_sec - prev_s) * 1000000 + (tv.tv_usec - prev_us)) / 1000; if (packet->tick > next_tick) next_tick += 65536; if ((out->p == out->end) || duration > next_tick - packet->tick + 500) { unsigned int delay_us; prev_s = tv.tv_sec; prev_us = tv.tv_usec; if (abs((next_tick - packet->tick) - duration) > 20) { DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick)); DEBUG(("last: %d, is: %d, should: %d\n", packet->tick, (packet->tick + duration) % 65536, next_tick % 65536)); } delay_us = ((out->size / 4) * (1000000 / 44100)); rdpsnd_queue_next(delay_us); } } struct audio_driver * libao_register(char *options) { static struct audio_driver libao_driver; memset(&libao_driver, 0, sizeof(libao_driver)); libao_driver.name = "libao"; libao_driver.description = "libao output driver, default device: system dependent"; libao_driver.add_fds = libao_add_fds; libao_driver.check_fds = libao_check_fds; libao_driver.wave_out_open = libao_open; libao_driver.wave_out_close = libao_close; libao_driver.wave_out_format_supported = rdpsnd_dsp_resample_supported; libao_driver.wave_out_set_format = libao_set_format; libao_driver.wave_out_volume = rdpsnd_dsp_softvol_set; libao_driver.need_byteswap_on_be = 1; libao_driver.need_resampling = 1; if (options) { libao_device = xstrdup(options); } return &libao_driver; } rdesktop-1.8.3/rdpsnd_oss.c0000664000770100510440000002413012053355346014625 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Sound Channel Process Functions - Open Sound System Copyright (C) Matthew Chapman 2003-2008 Copyright (C) GuoJunBo 2003 Copyright 2006-2008 Pierre Ossman for Cendio AB Copyright 2005-2011 Peter Astrand for Cendio AB 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 3 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, see . */ /* This is a workaround for Esound bug 312665. FIXME: Remove this when Esound is fixed. */ #ifdef _FILE_OFFSET_BITS #undef _FILE_OFFSET_BITS #endif #include #include "rdesktop.h" #include "rdpsnd.h" #include "rdpsnd_dsp.h" #include #include #include #include #include #include #include #include #include #define DEFAULTDEVICE "/dev/dsp" #define MAX_LEN 512 static int dsp_fd = -1; static int dsp_mode; static RD_BOOL dsp_configured; static RD_BOOL dsp_broken; static int stereo; static int format; static uint32 snd_rate; static short samplewidth; static char *dsp_dev; static RD_BOOL in_esddsp; /* This is a just a forward declaration */ static struct audio_driver oss_driver; static void oss_play(void); static void oss_record(void); static RD_BOOL oss_set_format(RD_WAVEFORMATEX * pwfx); static void oss_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { if (dsp_fd == -1) return; if ((dsp_mode == O_WRONLY || dsp_mode == O_RDWR) && !rdpsnd_queue_empty()) FD_SET(dsp_fd, wfds); if (dsp_mode == O_RDONLY || dsp_mode == O_RDWR) FD_SET(dsp_fd, rfds); if (dsp_fd > *n) *n = dsp_fd; } static void oss_check_fds(fd_set * rfds, fd_set * wfds) { if (FD_ISSET(dsp_fd, wfds)) oss_play(); if (FD_ISSET(dsp_fd, rfds)) oss_record(); } static RD_BOOL detect_esddsp(void) { struct stat s; char *preload; if (fstat(dsp_fd, &s) == -1) return False; if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) return False; preload = getenv("LD_PRELOAD"); if (preload == NULL) return False; if (strstr(preload, "esddsp") == NULL) return False; return True; } static void oss_restore_format() { RD_WAVEFORMATEX wfx; memset(&wfx, 0, sizeof(RD_WAVEFORMATEX)); switch (format) { case AFMT_U8: wfx.wBitsPerSample = 8; break; case AFMT_S16_LE: wfx.wBitsPerSample = 16; break; default: wfx.wBitsPerSample = 0; } wfx.nChannels = stereo ? 2 : 1; wfx.nSamplesPerSec = snd_rate; oss_set_format(&wfx); } static RD_BOOL oss_open(int wanted) { if (dsp_fd != -1) { if (wanted == dsp_mode) { /* should probably not happen */ return True; } else { /* device open but not our mode. Before reopening O_RDWR, verify that the device is duplex capable */ int caps; ioctl(dsp_fd, SNDCTL_DSP_SETDUPLEX, 0); if ((ioctl(dsp_fd, SNDCTL_DSP_GETCAPS, &caps) < 0) || !(caps & DSP_CAP_DUPLEX)) { warning("This device is not capable of full duplex operation.\n"); return False; } close(dsp_fd); dsp_mode = O_RDWR; } } else { dsp_mode = wanted; } dsp_configured = False; dsp_broken = False; dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK); if (dsp_fd == -1) { perror(dsp_dev); return False; } in_esddsp = detect_esddsp(); return True; } static void oss_close(void) { close(dsp_fd); dsp_fd = -1; } static RD_BOOL oss_open_out(void) { if (!oss_open(O_WRONLY)) return False; return True; } static void oss_close_out(void) { oss_close(); if (dsp_mode == O_RDWR) { if (oss_open(O_RDONLY)) oss_restore_format(); } /* Ack all remaining packets */ while (!rdpsnd_queue_empty()) rdpsnd_queue_next(0); } static RD_BOOL oss_open_in(void) { if (!oss_open(O_RDONLY)) return False; return True; } static void oss_close_in(void) { oss_close(); if (dsp_mode == O_RDWR) { if (oss_open(O_WRONLY)) oss_restore_format(); } } static RD_BOOL oss_format_supported(RD_WAVEFORMATEX * pwfx) { if (pwfx->wFormatTag != WAVE_FORMAT_PCM) return False; if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2)) return False; if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16)) return False; return True; } static RD_BOOL oss_set_format(RD_WAVEFORMATEX * pwfx) { int fragments; static RD_BOOL driver_broken = False; assert(dsp_fd != -1); if (dsp_configured) { if ((pwfx->wBitsPerSample == 8) && (format != AFMT_U8)) return False; if ((pwfx->wBitsPerSample == 16) && (format != AFMT_S16_LE)) return False; if ((pwfx->nChannels == 2) != ! !stereo) return False; if (pwfx->nSamplesPerSec != snd_rate) return False; return True; } ioctl(dsp_fd, SNDCTL_DSP_RESET, NULL); ioctl(dsp_fd, SNDCTL_DSP_SYNC, NULL); if (pwfx->wBitsPerSample == 8) format = AFMT_U8; else if (pwfx->wBitsPerSample == 16) format = AFMT_S16_LE; samplewidth = pwfx->wBitsPerSample / 8; if (ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1) { perror("SNDCTL_DSP_SETFMT"); oss_close(); return False; } if (pwfx->nChannels == 2) { stereo = 1; samplewidth *= 2; } else { stereo = 0; } if (ioctl(dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1) { perror("SNDCTL_DSP_CHANNELS"); oss_close(); return False; } oss_driver.need_resampling = 0; snd_rate = pwfx->nSamplesPerSec; if (ioctl(dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1) { uint32 rates[] = { 44100, 48000, 0 }; uint32 *prates = rates; while (*prates != 0) { if ((pwfx->nSamplesPerSec != *prates) && (ioctl(dsp_fd, SNDCTL_DSP_SPEED, prates) != -1)) { oss_driver.need_resampling = 1; snd_rate = *prates; if (rdpsnd_dsp_resample_set (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False) { error("rdpsnd_dsp_resample_set failed"); oss_close(); return False; } break; } prates++; } if (*prates == 0) { perror("SNDCTL_DSP_SPEED"); oss_close(); return False; } } /* try to get 12 fragments of 2^12 bytes size */ fragments = (12 << 16) + 12; ioctl(dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments); if (!driver_broken) { audio_buf_info info; memset(&info, 0, sizeof(info)); if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1) { perror("SNDCTL_DSP_GETOSPACE"); oss_close(); return False; } if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0) { fprintf(stderr, "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n", info.fragments, info.fragstotal, info.fragsize); driver_broken = True; } } dsp_configured = True; return True; } static void oss_volume(uint16 left, uint16 right) { uint32 volume; volume = left / (65536 / 100); volume |= right / (65536 / 100) << 8; if (ioctl(dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1) { warning("hardware volume control unavailable, falling back to software volume control!\n"); oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set; rdpsnd_dsp_softvol_set(left, right); return; } } static void oss_play(void) { struct audio_packet *packet; ssize_t len; STREAM out; assert(dsp_fd != -1); /* We shouldn't be called if the queue is empty, but still */ if (rdpsnd_queue_empty()) return; packet = rdpsnd_queue_current_packet(); out = &packet->s; len = out->end - out->p; len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len); if (len == -1) { if (errno != EWOULDBLOCK) { if (!dsp_broken) perror("RDPSND: write()"); dsp_broken = True; rdpsnd_queue_next(0); } return; } dsp_broken = False; out->p += len; if (out->p == out->end) { int delay_bytes; unsigned long delay_us; audio_buf_info info; if (in_esddsp) { /* EsounD has no way of querying buffer status, so we have to * go with a fixed size. */ delay_bytes = out->size; } else { #ifdef SNDCTL_DSP_GETODELAY delay_bytes = 0; if (ioctl(dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1) delay_bytes = -1; #else delay_bytes = -1; #endif if (delay_bytes == -1) { if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1) delay_bytes = info.fragstotal * info.fragsize - info.bytes; else delay_bytes = out->size; } } delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate)); rdpsnd_queue_next(delay_us); } } static void oss_record(void) { char buffer[32768]; int len; assert(dsp_fd != -1); len = read(dsp_fd, buffer, sizeof(buffer)); if (len == -1) { if (errno != EWOULDBLOCK) { if (!dsp_broken) perror("RDPSND: read()"); dsp_broken = True; rdpsnd_queue_next(0); } return; } dsp_broken = False; rdpsnd_record(buffer, len); } struct audio_driver * oss_register(char *options) { memset(&oss_driver, 0, sizeof(oss_driver)); oss_driver.name = "oss"; oss_driver.description = "OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV"; oss_driver.add_fds = oss_add_fds; oss_driver.check_fds = oss_check_fds; oss_driver.wave_out_open = oss_open_out; oss_driver.wave_out_close = oss_close_out; oss_driver.wave_out_format_supported = oss_format_supported; oss_driver.wave_out_set_format = oss_set_format; oss_driver.wave_out_volume = oss_volume; oss_driver.wave_in_open = oss_open_in; oss_driver.wave_in_close = oss_close_in; oss_driver.wave_in_format_supported = oss_format_supported; oss_driver.wave_in_set_format = oss_set_format; oss_driver.wave_in_volume = NULL; /* FIXME */ oss_driver.need_byteswap_on_be = 0; oss_driver.need_resampling = 0; if (options) { dsp_dev = xstrdup(options); } else { dsp_dev = getenv("AUDIODEV"); if (dsp_dev == NULL) { dsp_dev = DEFAULTDEVICE; } } return &oss_driver; } rdesktop-1.8.3/rdpsnd_sgi.c0000664000770100510440000001642311551304323014600 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Sound Channel Process Functions - SGI/IRIX Copyright (C) Matthew Chapman 2003-2008 Copyright (C) GuoJunBo 2003 Copyright (C) Jeremy Meng 2004-2005 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 3 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, see . */ #include "rdesktop.h" #include #include /* #define IRIX_DEBUG 1 */ #define IRIX_MAX_VOL 65535 ALconfig audioconfig; ALport output_port; static int g_snd_rate; static int width = AL_SAMPLE_16; static char *sgi_output_device = NULL; double min_volume, max_volume, volume_range; int resource, maxFillable; int combinedFrameSize; void sgi_play(void); void sgi_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { /* We need to be called rather often... */ if (output_port != (ALport) 0 && !rdpsnd_queue_empty()) FD_SET(0, wfds); } void sgi_check_fds(fd_set * rfds, fd_set * wfds) { if (output_port == (ALport) 0) return; if (!rdpsnd_queue_empty()) sgi_play(); } RD_BOOL sgi_open(void) { ALparamInfo pinfo; static int warned = 0; #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_open: begin\n"); #endif if (!warned && sgi_output_device) { warning("device-options not supported for libao-driver\n"); warned = 1; } if (alGetParamInfo(AL_DEFAULT_OUTPUT, AL_GAIN, &pinfo) < 0) { fprintf(stderr, "sgi_open: alGetParamInfo failed: %s\n", alGetErrorString(oserror())); } min_volume = alFixedToDouble(pinfo.min.ll); max_volume = alFixedToDouble(pinfo.max.ll); volume_range = (max_volume - min_volume); #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_open: minvol = %lf, maxvol= %lf, range = %lf.\n", min_volume, max_volume, volume_range); #endif audioconfig = alNewConfig(); if (audioconfig == (ALconfig) 0) { fprintf(stderr, "sgi_open: alNewConfig failed: %s\n", alGetErrorString(oserror())); return False; } output_port = alOpenPort("rdpsnd", "w", 0); if (output_port == (ALport) 0) { fprintf(stderr, "sgi_open: alOpenPort failed: %s\n", alGetErrorString(oserror())); return False; } #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_open: returning\n"); #endif return True; } void sgi_close(void) { /* Ack all remaining packets */ #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_close: begin\n"); #endif while (!rdpsnd_queue_empty()) rdpsnd_queue_next(0); alDiscardFrames(output_port, 0); alClosePort(output_port); output_port = (ALport) 0; alFreeConfig(audioconfig); #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_close: returning\n"); #endif } RD_BOOL sgi_format_supported(RD_WAVEFORMATEX * pwfx) { if (pwfx->wFormatTag != WAVE_FORMAT_PCM) return False; if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2)) return False; if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16)) return False; return True; } RD_BOOL sgi_set_format(RD_WAVEFORMATEX * pwfx) { int channels; int frameSize, channelCount; ALpv params; #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_set_format: init...\n"); #endif if (pwfx->wBitsPerSample == 8) width = AL_SAMPLE_8; else if (pwfx->wBitsPerSample == 16) width = AL_SAMPLE_16; /* Limited support to configure an opened audio port in IRIX. The number of channels is a static setting and can not be changed after a port is opened. So if the number of channels remains the same, we can configure other settings; otherwise we have to reopen the audio port, using same config. */ channels = pwfx->nChannels; g_snd_rate = pwfx->nSamplesPerSec; alSetSampFmt(audioconfig, AL_SAMPFMT_TWOSCOMP); alSetWidth(audioconfig, width); if (channels != alGetChannels(audioconfig)) { alClosePort(output_port); alSetChannels(audioconfig, channels); output_port = alOpenPort("rdpsnd", "w", audioconfig); if (output_port == (ALport) 0) { fprintf(stderr, "sgi_set_format: alOpenPort failed: %s\n", alGetErrorString(oserror())); return False; } } resource = alGetResource(output_port); maxFillable = alGetFillable(output_port); channelCount = alGetChannels(audioconfig); frameSize = alGetWidth(audioconfig); if (frameSize == 0 || channelCount == 0) { fprintf(stderr, "sgi_set_format: bad frameSize or channelCount\n"); return False; } combinedFrameSize = frameSize * channelCount; params.param = AL_RATE; params.value.ll = (long long) g_snd_rate << 32; if (alSetParams(resource, ¶ms, 1) < 0) { fprintf(stderr, "wave_set_format: alSetParams failed: %s\n", alGetErrorString(oserror())); return False; } if (params.sizeOut < 0) { fprintf(stderr, "wave_set_format: invalid rate %d\n", g_snd_rate); return False; } #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_set_format: returning...\n"); #endif return True; } void sgi_volume(uint16 left, uint16 right) { double gainleft, gainright; ALpv pv[1]; ALfixed gain[8]; #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_volume: begin\n"); fprintf(stderr, "left='%d', right='%d'\n", left, right); #endif gainleft = (double) left / IRIX_MAX_VOL; gainright = (double) right / IRIX_MAX_VOL; gain[0] = alDoubleToFixed(min_volume + gainleft * volume_range); gain[1] = alDoubleToFixed(min_volume + gainright * volume_range); pv[0].param = AL_GAIN; pv[0].value.ptr = gain; pv[0].sizeIn = 8; if (alSetParams(AL_DEFAULT_OUTPUT, pv, 1) < 0) { fprintf(stderr, "sgi_volume: alSetParams failed: %s\n", alGetErrorString(oserror())); return; } #if (defined(IRIX_DEBUG)) fprintf(stderr, "sgi_volume: returning\n"); #endif } void sgi_play(void) { struct audio_packet *packet; ssize_t len; unsigned int i; STREAM out; int gf; while (1) { if (rdpsnd_queue_empty()) return; packet = rdpsnd_queue_current_packet(); out = &packet->s; len = out->end - out->p; alWriteFrames(output_port, out->p, len / combinedFrameSize); out->p += len; if (out->p == out->end) { gf = alGetFilled(output_port); if (gf < (4 * maxFillable / 10)) { rdpsnd_queue_next(0); } else { #if (defined(IRIX_DEBUG)) /* fprintf(stderr,"Busy playing...\n"); */ #endif usleep(10); return; } } } } struct audio_driver * sgi_register(char *options) { static struct audio_driver sgi_driver; memset(&sgi_driver, 0, sizeof(sgi_driver)); sgi_driver.name = "sgi"; sgi_driver.description = "SGI output driver"; sgi_driver.add_fds = sgi_add_fds; sgi_driver.check_fds = sgi_check_fds; sgi_driver.wave_out_open = sgi_open; sgi_driver.wave_out_close = sgi_close; sgi_driver.wave_out_format_supported = sgi_format_supported; sgi_driver.wave_out_set_format = sgi_set_format; sgi_driver.wave_out_volume = sgi_volume; sgi_driver.need_byteswap_on_be = 1; sgi_driver.need_resampling = 0; if (options) { sgi_output_device = xstrdup(options); } return &sgi_driver; } rdesktop-1.8.3/rdpsnd_sun.c0000664000770100510440000002331112053355346014626 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Sound Channel Process Functions - Sun Copyright (C) Matthew Chapman 2003-2008 Copyright (C) GuoJunBo 2003 Copyright (C) Michael Gernoth 2003-2008 Copyright 2007-2008 Pierre Ossman for Cendio AB Copyright 2008-2011 Peter Astrand for Cendio AB 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 3 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, see . */ #include "rdesktop.h" #include "rdpsnd.h" #include #include #include #include #include #include #if (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #include #endif #define DEFAULTDEVICE "/dev/audio" #define MAX_LEN 512 static int dsp_fd = -1; static int dsp_mode; static int dsp_refs; static RD_BOOL dsp_configured; static RD_BOOL dsp_broken; static RD_BOOL broken_2_channel_record = False; static RD_BOOL dsp_out; static RD_BOOL dsp_in; static int stereo; static int format; static uint32 snd_rate; static short samplewidth; static char *dsp_dev; static uint_t written_samples; void sun_play(void); void sun_record(void); static int sun_pause(void) { audio_info_t info; AUDIO_INITINFO(&info); info.record.pause = 1; if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1) return -1; #if defined I_FLUSH && defined FLUSHR if (ioctl(dsp_fd, I_FLUSH, FLUSHR) == -1) return -1; #endif return 0; } static int sun_resume(void) { audio_info_t info; AUDIO_INITINFO(&info); info.record.pause = 0; if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1) return -1; return 0; } void sun_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { if (dsp_fd == -1) return; if (dsp_out && !rdpsnd_queue_empty()) FD_SET(dsp_fd, wfds); if (dsp_in) FD_SET(dsp_fd, rfds); if (dsp_fd > *n) *n = dsp_fd; } void sun_check_fds(fd_set * rfds, fd_set * wfds) { if (FD_ISSET(dsp_fd, wfds)) sun_play(); if (FD_ISSET(dsp_fd, rfds)) sun_record(); } RD_BOOL sun_open(int mode) { audio_info_t info; if (dsp_fd != -1) { dsp_refs++; if (dsp_mode == O_RDWR) return True; if (dsp_mode == mode) return True; dsp_refs--; return False; } dsp_configured = False; dsp_broken = False; written_samples = 0; dsp_mode = O_RDWR; dsp_fd = open(dsp_dev, O_RDWR | O_NONBLOCK); if (dsp_fd != -1) { AUDIO_INITINFO(&info); if ((ioctl(dsp_fd, AUDIO_GETINFO, &info) == -1) || !(info.hw_features & AUDIO_HWFEATURE_DUPLEX)) { close(dsp_fd); dsp_fd = -1; } } if (dsp_fd == -1) { dsp_mode = mode; dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK); if (dsp_fd == -1) { perror(dsp_dev); return False; } } /* * Pause recording until we actually start using it. */ if (dsp_mode != O_WRONLY) { if (sun_pause() == -1) { close(dsp_fd); dsp_fd = -1; return False; } } dsp_refs++; return True; } void sun_close(void) { dsp_refs--; if (dsp_refs != 0) return; close(dsp_fd); dsp_fd = -1; } RD_BOOL sun_open_out(void) { if (!sun_open(O_WRONLY)) return False; dsp_out = True; return True; } void sun_close_out(void) { #if defined I_FLUSH && defined FLUSHW /* Flush the audiobuffer */ ioctl(dsp_fd, I_FLUSH, FLUSHW); #endif #if defined AUDIO_FLUSH ioctl(dsp_fd, AUDIO_FLUSH, NULL); #endif sun_close(); /* Ack all remaining packets */ while (!rdpsnd_queue_empty()) rdpsnd_queue_next(0); dsp_out = False; } RD_BOOL sun_open_in(void) { #if ! (defined I_FLUSH && defined FLUSHR) /* * It is not possible to reliably use the recording without * flush operations. */ return False; #endif if (!sun_open(O_RDONLY)) return False; /* 2 channel recording is known to be broken on Solaris x86 Sun Ray systems */ #ifdef L_ENDIAN if (strstr(dsp_dev, "/utaudio/")) broken_2_channel_record = True; #endif /* * Unpause the stream now that we have someone using it. */ if (sun_resume() == -1) { sun_close(); return False; } dsp_in = True; return True; } void sun_close_in(void) { /* * Repause the stream when the user goes away. */ sun_pause(); sun_close(); dsp_in = False; } RD_BOOL sun_format_supported(RD_WAVEFORMATEX * pwfx) { if (pwfx->wFormatTag != WAVE_FORMAT_PCM) return False; if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2)) return False; if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16)) return False; return True; } RD_BOOL sun_set_format(RD_WAVEFORMATEX * pwfx) { audio_info_t info; ioctl(dsp_fd, AUDIO_DRAIN, 0); AUDIO_INITINFO(&info); if (dsp_configured) { if ((pwfx->wBitsPerSample == 8) && (format != AUDIO_ENCODING_LINEAR8)) return False; if ((pwfx->wBitsPerSample == 16) && (format != AUDIO_ENCODING_LINEAR)) return False; if ((pwfx->nChannels == 2) != ! !stereo) return False; if (pwfx->nSamplesPerSec != snd_rate) return False; return True; } sun_pause(); if (pwfx->wBitsPerSample == 8) format = AUDIO_ENCODING_LINEAR8; else if (pwfx->wBitsPerSample == 16) format = AUDIO_ENCODING_LINEAR; samplewidth = pwfx->wBitsPerSample / 8; info.play.channels = pwfx->nChannels; info.record.channels = info.play.channels; if (pwfx->nChannels == 1) { stereo = 0; } else if (pwfx->nChannels == 2) { stereo = 1; samplewidth *= 2; if (broken_2_channel_record) { info.record.channels = 1; } } snd_rate = pwfx->nSamplesPerSec; info.play.sample_rate = pwfx->nSamplesPerSec; info.play.precision = pwfx->wBitsPerSample; info.play.encoding = format; info.play.samples = 0; info.play.eof = 0; info.play.error = 0; info.record.sample_rate = info.play.sample_rate; info.record.precision = info.play.precision; info.record.encoding = info.play.encoding; info.record.samples = 0; info.record.error = 0; if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1) { perror("AUDIO_SETINFO"); sun_close(); return False; } dsp_configured = True; if (dsp_in) sun_resume(); return True; } void sun_volume(uint16 left, uint16 right) { audio_info_t info; uint balance; uint volume; AUDIO_INITINFO(&info); volume = (left > right) ? left : right; if (volume / AUDIO_MID_BALANCE != 0) { balance = AUDIO_MID_BALANCE - (left / (volume / AUDIO_MID_BALANCE)) + (right / (volume / AUDIO_MID_BALANCE)); } else { balance = AUDIO_MID_BALANCE; } info.play.gain = volume / (65536 / AUDIO_MAX_GAIN); info.play.balance = balance; if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1) { perror("AUDIO_SETINFO"); return; } } void sun_play(void) { struct audio_packet *packet; ssize_t len; STREAM out; /* We shouldn't be called if the queue is empty, but still */ if (rdpsnd_queue_empty()) return; packet = rdpsnd_queue_current_packet(); out = &packet->s; len = out->end - out->p; len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len); if (len == -1) { if (errno != EWOULDBLOCK) { if (!dsp_broken) perror("RDPSND: write()"); dsp_broken = True; rdpsnd_queue_next(0); } return; } written_samples += len / (samplewidth * (stereo ? 2 : 1)); dsp_broken = False; out->p += len; if (out->p == out->end) { audio_info_t info; uint_t delay_samples; unsigned long delay_us; if (ioctl(dsp_fd, AUDIO_GETINFO, &info) != -1) delay_samples = written_samples - info.play.samples; else delay_samples = out->size / (samplewidth * (stereo ? 2 : 1)); delay_us = delay_samples * (1000000 / snd_rate); rdpsnd_queue_next(delay_us); } } void sun_record(void) { char buffer[32768]; int len; len = read(dsp_fd, buffer, sizeof(buffer) / 2); if (len == -1) { if (errno != EWOULDBLOCK) perror("read audio"); return; } if (broken_2_channel_record) { unsigned int i; int rec_samplewidth = samplewidth / 2; /* Loop over each byte read backwards and put in place */ i = len - 1; do { int samples_before = i / rec_samplewidth * 2; int sample_byte = i % rec_samplewidth; int ch1_offset = samples_before * rec_samplewidth + sample_byte; // Channel 1 buffer[ch1_offset] = buffer[i]; // Channel 2 buffer[ch1_offset + rec_samplewidth] = buffer[i]; i--; } while (i); len *= 2; } rdpsnd_record(buffer, len); } struct audio_driver * sun_register(char *options) { static struct audio_driver sun_driver; memset(&sun_driver, 0, sizeof(sun_driver)); sun_driver.name = "sun"; sun_driver.description = "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV"; sun_driver.add_fds = sun_add_fds; sun_driver.check_fds = sun_check_fds; sun_driver.wave_out_open = sun_open_out; sun_driver.wave_out_close = sun_close_out; sun_driver.wave_out_format_supported = sun_format_supported; sun_driver.wave_out_set_format = sun_set_format; sun_driver.wave_out_volume = sun_volume; sun_driver.wave_in_open = sun_open_in; sun_driver.wave_in_close = sun_close_in; sun_driver.wave_in_format_supported = sun_format_supported; sun_driver.wave_in_set_format = sun_set_format; sun_driver.wave_in_volume = NULL; /* FIXME */ sun_driver.need_byteswap_on_be = 1; sun_driver.need_resampling = 0; if (options) { dsp_dev = xstrdup(options); } else { dsp_dev = getenv("AUDIODEV"); if (dsp_dev == NULL) { dsp_dev = DEFAULTDEVICE; } } return &sun_driver; } rdesktop-1.8.3/scard.c0000664000770100510440000020375612404306606013553 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Smart Card support Copyright (C) Alexi Volkov 2006 Copyright 2010-2013 Pierre Ossman for Cendio AB Copyright 2011-2014 Henrik Andersson for Cendio AB 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 3 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, see . */ #include #include #include #include #include #include #include #include #ifndef MAKE_PROTO #ifdef __APPLE__ #include #include #include #else #include #include #include #ifdef PCSCLITE_VERSION_NUMBER #include #endif #endif /* PCSC_OSX */ #include "rdesktop.h" #include "scard.h" /* variable segment */ #define SCARD_MAX_MEM 102400 #ifndef SCARD_AUTOALLOCATE #define SCARD_AUTOALLOCATE -1 #endif #define OUT_STREAM_SIZE 4096 #ifdef B_ENDIAN #define swap32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | \ (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24)) #define swap16(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) #else #define swap32(x) (x) #define swap16(x) (x) #endif static pthread_mutex_t **scard_mutex = NULL; static uint32 curEpoch = 0, curDevice = 0, curId = 0, curBytesOut = 0; static PSCNameMapRec nameMapList = NULL; static int nameMapCount = 0; static pthread_t queueHandler; static pthread_mutex_t queueAccess; static pthread_cond_t queueEmpty; static pthread_mutex_t hcardAccess; static PMEM_HANDLE threadListHandle = NULL; static PThreadListElement threadList = NULL; static PSCThreadData queueFirst = NULL, queueLast = NULL; static int threadCount = 0; static PSCHCardRec hcardFirst = NULL; static void *queue_handler_function(void *data); /* code segment */ #endif /* MAKE_PROTO */ void scardSetInfo(uint32 epoch, uint32 device, uint32 id, uint32 bytes_out) { curDevice = device; curId = id; curBytesOut = bytes_out; curEpoch = epoch; } #ifndef MAKE_PROTO static RD_NTSTATUS scard_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle) { return RD_STATUS_SUCCESS; } static RD_NTSTATUS scard_close(RD_NTHANDLE handle) { return RD_STATUS_SUCCESS; } static RD_NTSTATUS scard_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { return RD_STATUS_SUCCESS; } static RD_NTSTATUS scard_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { return RD_STATUS_SUCCESS; } #endif /* MAKE_PROTO */ /* Enumeration of devices from rdesktop.c */ /* returns numer of units found and initialized. */ /* optarg looks like ':"ReaderName=ReaderAlias"' */ /* when it arrives to this function. */ int scard_enum_devices(uint32 * id, char *optarg) { char *name = optarg + 1; char *alias; int count = 0; PSCNameMapRec tmpMap; MYPCSC_DWORD rv; SCARDCONTEXT hContext; /* code segment */ rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if (rv != SCARD_S_SUCCESS) { error("scard_enum_devices: PCSC service not available\n"); return 0; } else rv = SCardReleaseContext(hContext); count = 0; if (0 != pthread_mutex_init(&queueAccess, NULL)) { error("scard_enum_devices: Can't initialize queue access mutex\n"); return 0; } if (0 != pthread_cond_init(&queueEmpty, NULL)) { error("scard_enum_devices: Can't initialize queue control cv\n"); return 0; } if (0 != pthread_mutex_init(&hcardAccess, NULL)) { error("scard_enum_devices: Can't initialize hcard list access mutex\n"); return 0; } if (0 != pthread_create(&queueHandler, NULL, (void *(*)(void *)) queue_handler_function, NULL)) { error("scard_enum_devices: Can't create queue handling Thread\n"); return 0; } strncpy(g_rdpdr_device[*id].name, "SCARD\0\0\0", 8); toupper_str(g_rdpdr_device[*id].name); g_rdpdr_device[*id].local_path = "/dev/scard"; g_rdpdr_device[*id].pdevice_data = NULL; g_rdpdr_device[*id].handle = 0; g_rdpdr_device[*id].device_type = DEVICE_TYPE_SCARD; count++; (*id)++; if (*optarg == ':') { while ((optarg = next_arg(name, ',')) && *id < RDPDR_MAX_DEVICES) { int len; char *vendor = NULL; alias = next_arg(name, '='); vendor = next_arg(alias, ';'); if (strlen(name) > 0) { if (!strlen(alias)) { alias = name; vendor = "\0"; } printf("Static/aliased Device:\n"); printf(" Lin name: [%s]\n", name); printf(" Win name: [%s]\n", alias); printf(" Vendor : [%s]\n", vendor); nameMapCount++; if (nameMapList == NULL) nameMapList = xmalloc(nameMapCount * sizeof(TSCNameMapRec)); else nameMapList = xrealloc(nameMapList, nameMapCount * sizeof(TSCNameMapRec)); tmpMap = nameMapList + nameMapCount - 1; len = strlen(alias); strncpy(tmpMap->alias, alias, (len > 127) ? (127) : (len)); len = strlen(name); strncpy(tmpMap->name, name, (len > 127) ? (127) : (len)); if (vendor) { len = strlen(vendor); if (len > 0) { memset(tmpMap->vendor, 0, 128); strncpy(tmpMap->vendor, vendor, (len > 127) ? (127) : (len)); } else tmpMap->vendor[0] = '\0'; } else tmpMap->vendor[0] = '\0'; } name = optarg; } } return count; } #ifndef MAKE_PROTO typedef struct _scard_handle_list_t { struct _scard_handle_list_t *next; /* pcsc handles is datatype long which is arch sizedependent */ long handle; /* rdp server handles are always 32bit */ uint32_t server; } _scard_handle_list_t; static uint32_t g_scard_handle_counter = 0; static _scard_handle_list_t *g_scard_handle_list = NULL; static void _scard_handle_list_add(long handle); static void _scard_handle_list_remove(long handle); static uint32_t _scard_handle_list_get_server_handle(long handle); static long _scard_handle_list_get_pcsc_handle(uint32_t server); void _scard_handle_list_add(long handle) { _scard_handle_list_t *list = g_scard_handle_list; /* we dont care of order of list so to simplify the add we add new items to front of list */ _scard_handle_list_t *item = xmalloc(sizeof(_scard_handle_list_t)); item->next = list; item->handle = handle; /* lookup first unused handle id */ int overlap = 0; if (g_scard_handle_counter == 0) g_scard_handle_counter++; while (_scard_handle_list_get_pcsc_handle(g_scard_handle_counter)) { g_scard_handle_counter++; if (g_scard_handle_counter == 0 && overlap) assert(!"broken smartcard client software, handles are not freed and there is no more handles left to allocate."); if (g_scard_handle_counter == 0) overlap = g_scard_handle_counter = 1; } item->server = g_scard_handle_counter; g_scard_handle_list = item; } void _scard_handle_list_remove(long handle) { _scard_handle_list_t *item, *list, *prev_item; prev_item = NULL; item = list = g_scard_handle_list; while (item) { if (item->handle == handle) { /* unlink from list */ if (prev_item) prev_item->next = item->next; else g_scard_handle_list = item->next; xfree(item); break; } /* store previous item for relinking */ prev_item = item; item = item->next; } } uint32_t _scard_handle_list_get_server_handle(long handle) { _scard_handle_list_t *item; item = g_scard_handle_list; while (item) { if (item->handle == handle) return item->server; item = item->next; } return 0; } long _scard_handle_list_get_pcsc_handle(uint32_t server) { _scard_handle_list_t *item; item = g_scard_handle_list; while (item) { if (item->server == server) return item->handle; item = item->next; } return 0; } static void * SC_xmalloc(PMEM_HANDLE * memHandle, unsigned int size) { PMEM_HANDLE handle = NULL; if (size > 0 && memHandle) { handle = xmalloc(size + sizeof(MEM_HANDLE)); if (handle) { handle->prevHandle = NULL; handle->nextHandle = NULL; handle->dataSize = size; if (*memHandle) { handle->prevHandle = *memHandle; (*memHandle)->nextHandle = handle; } *memHandle = handle; return handle + 1; } else return NULL; } else return NULL; } static void SC_xfree(PMEM_HANDLE * handle, void *memptr) { if (memptr != NULL) { PMEM_HANDLE lcHandle = (PMEM_HANDLE) memptr - 1; if (lcHandle->dataSize > 0) { memset(memptr, 0, lcHandle->dataSize); if (lcHandle->nextHandle) lcHandle->nextHandle->prevHandle = lcHandle->prevHandle; if (lcHandle->prevHandle) lcHandle->prevHandle->nextHandle = lcHandle->nextHandle; if (*handle == lcHandle) { if (lcHandle->prevHandle) *handle = lcHandle->prevHandle; else *handle = lcHandle->nextHandle; } xfree(lcHandle); } } } static void SC_xfreeallmemory(PMEM_HANDLE * handle) { if (handle && (*handle)) { if ((*handle)->prevHandle) { (*handle)->prevHandle->nextHandle = NULL; SC_xfreeallmemory(&((*handle)->prevHandle)); } if ((*handle)->nextHandle) { (*handle)->nextHandle->prevHandle = NULL; SC_xfreeallmemory(&((*handle)->nextHandle)); } memset(*handle, 0, (*handle)->dataSize + sizeof(MEM_HANDLE)); xfree(*handle); *handle = NULL; } } /* ---------------------------------- */ static char * getName(char *alias) { int i; PSCNameMapRec tmpMap; for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { if (strcmp(tmpMap->alias, alias) == 0) return tmpMap->name; } return alias; } static char * getVendor(char *name) { int i; PSCNameMapRec tmpMap; for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { if (strcmp(tmpMap->name, name) == 0) return tmpMap->vendor; } return NULL; } static char * getAlias(char *name) { int i; PSCNameMapRec tmpMap; for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { if (strcmp(tmpMap->name, name) == 0) return tmpMap->alias; } return name; } static int hasAlias(char *name) { int i; PSCNameMapRec tmpMap; for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { if (strcmp(tmpMap->name, name) == 0) return 1; } return 0; } static void inRepos(STREAM in, unsigned int read) { SERVER_DWORD add = 4 - read % 4; if (add < 4 && add > 0) { in_uint8s(in, add); } } static void outRepos(STREAM out, unsigned int written) { SERVER_DWORD add = (4 - written % 4) % 4; if (add > 0) { out_uint8s(out, add); } } static void outBufferStartWithLimit(STREAM out, int length, int highLimit) { int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length)); out_uint32_le(out, header); out_uint32_le(out, 0x00000001); /* Magic DWORD - any non zero */ } static void outBufferStart(STREAM out, int length) { outBufferStartWithLimit(out, length, 0x7FFFFFFF); } static void outBufferFinishWithLimit(STREAM out, char *buffer, unsigned int length, unsigned int highLimit) { int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length)); out_uint32_le(out, header); if (length <= 0) { out_uint32_le(out, 0x00000000); } else { if (header < length) length = header; out_uint8p(out, buffer, length); outRepos(out, length); } } static void outBufferFinish(STREAM out, char *buffer, unsigned int length) { outBufferFinishWithLimit(out, buffer, length, 0x7FFFFFFF); } static void outForceAlignment(STREAM out, unsigned int seed) { SERVER_DWORD add = (seed - (out->p - out->data) % seed) % seed; if (add > 0) out_uint8s(out, add); } static unsigned int inString(PMEM_HANDLE * handle, STREAM in, char **destination, SERVER_DWORD dataLength, RD_BOOL wide) { unsigned int Result = (wide) ? (2 * dataLength) : (dataLength); PMEM_HANDLE lcHandle = NULL; char *buffer = SC_xmalloc(&lcHandle, Result + 2); char *reader; /* code segment */ if (wide) { int i; in_uint8a(in, buffer, 2 * dataLength); for (i = 0; i < dataLength; i++) if ((buffer[2 * i] < 0) || (buffer[2 * i + 1] != 0)) buffer[i] = '?'; else buffer[i] = buffer[2 * i]; } else { in_uint8a(in, buffer, dataLength); } buffer[dataLength] = '\0'; reader = getName(buffer); *destination = SC_xmalloc(handle, strlen(reader) + 1); strcpy(*destination, reader); SC_xfreeallmemory(&lcHandle); return Result; } static unsigned int outString(STREAM out, char *source, RD_BOOL wide) { PMEM_HANDLE lcHandle = NULL; char *reader = getAlias(source); unsigned int dataLength = strlen(reader) + 1; unsigned int Result = (wide) ? (2 * dataLength) : (dataLength); /* code segment */ if (wide) { int i; char *buffer = SC_xmalloc(&lcHandle, Result); for (i = 0; i < dataLength; i++) { if (source[i] < 0) buffer[2 * i] = '?'; else buffer[2 * i] = reader[i]; buffer[2 * i + 1] = '\0'; } out_uint8p(out, buffer, 2 * dataLength); } else { out_uint8p(out, reader, dataLength); } SC_xfreeallmemory(&lcHandle); return Result; } static void inReaderName(PMEM_HANDLE * handle, STREAM in, char **destination, RD_BOOL wide) { SERVER_DWORD dataLength; in->p += 0x08; in_uint32_le(in, dataLength); inRepos(in, inString(handle, in, destination, dataLength, wide)); } static void inSkipLinked(STREAM in) { SERVER_DWORD len; in_uint32_le(in, len); if (len > 0) { in_uint8s(in, len); inRepos(in, len); } } /* ---------------------------------- */ /* Smart Card processing functions: */ /* ---------------------------------- */ static MYPCSC_DWORD SC_returnCode(MYPCSC_DWORD rc, PMEM_HANDLE * handle, STREAM in, STREAM out) { SC_xfreeallmemory(handle); out_uint8s(out, 256); return rc; } static MYPCSC_DWORD SC_returnNoMemoryError(PMEM_HANDLE * handle, STREAM in, STREAM out) { return SC_returnCode(SCARD_E_NO_MEMORY, handle, in, out); } static MYPCSC_DWORD TS_SCardEstablishContext(STREAM in, STREAM out) { MYPCSC_DWORD rv; MYPCSC_SCARDCONTEXT myHContext; SERVER_SCARDCONTEXT hContext; /* code segment */ DEBUG_SCARD(("SCARD: SCardEstablishContext()\n")); rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &myHContext); hContext = 0; if (myHContext) { _scard_handle_list_add(myHContext); hContext = _scard_handle_list_get_server_handle(myHContext); } if (rv) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success (context: 0x%08x [0x%lx])\n", hContext, myHContext)); } out_uint32_le(out, 0x00000004); out_uint32_le(out, hContext); /* must not be 0 (Seems to be pointer), don't know what is this (I use hContext as value) */ /* i hope it's not a pointer because i just downcasted it - jlj */ out_uint32_le(out, 0x00000004); out_uint32_le(out, hContext); outForceAlignment(out, 8); return rv; } static MYPCSC_DWORD TS_SCardReleaseContext(STREAM in, STREAM out) { MYPCSC_DWORD rv; MYPCSC_SCARDCONTEXT myHContext; SERVER_SCARDCONTEXT hContext; in->p += 0x1C; in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardReleaseContext(context: 0x%08x [0x%lx])\n", (unsigned) hContext, myHContext)); rv = SCardReleaseContext(myHContext); _scard_handle_list_remove(myHContext); if (rv) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success\n")); } outForceAlignment(out, 8); return rv; } static MYPCSC_DWORD TS_SCardIsValidContext(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; char *readers; DWORD readerCount = 1024; PMEM_HANDLE lcHandle = NULL; in->p += 0x1C; in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardIsValidContext(context: 0x%08x [0x%lx])\n", (unsigned) hContext, myHContext)); /* There is no realization of SCardIsValidContext in PC/SC Lite so we call SCardListReaders */ readers = SC_xmalloc(&lcHandle, 1024); if (!readers) return SC_returnNoMemoryError(&lcHandle, in, out); rv = SCardListReaders(myHContext, NULL, readers, &readerCount); if (rv) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); rv = SCARD_E_INVALID_HANDLE; } else { DEBUG_SCARD(("SCARD: -> Success\n")); } outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } static MYPCSC_DWORD TS_SCardListReaders(STREAM in, STREAM out, RD_BOOL wide) { #define readerArraySize 1024 MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; SERVER_DWORD dataLength; MYPCSC_DWORD cchReaders = readerArraySize; unsigned char *plen1, *plen2, *pend; char *readers, *cur; PMEM_HANDLE lcHandle = NULL; in->p += 0x2C; in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardListReaders(context: 0x%08x [0x%lx])\n", (unsigned) hContext, myHContext)); plen1 = out->p; out_uint32_le(out, 0x00000000); /* Temp value for data length as 0x0 */ out_uint32_le(out, 0x01760650); plen2 = out->p; out_uint32_le(out, 0x00000000); /* Temp value for data length as 0x0 */ dataLength = 0; readers = SC_xmalloc(&lcHandle, readerArraySize); if (!readers) return SC_returnNoMemoryError(&lcHandle, in, out); readers[0] = '\0'; readers[1] = '\0'; rv = SCardListReaders(myHContext, NULL, readers, &cchReaders); cur = readers; if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { int i; PSCNameMapRec tmpMap; DEBUG_SCARD(("SCARD: -> Success\n")); for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { dataLength += outString(out, tmpMap->alias, wide); } int lenSC = strlen(cur); if (lenSC == 0) dataLength += outString(out, "\0", wide); else while (lenSC > 0) { if (!hasAlias(cur)) { DEBUG_SCARD(("SCARD: \"%s\"\n", cur)); dataLength += outString(out, cur, wide); } cur = (void *) ((unsigned char *) cur + lenSC + 1); lenSC = strlen(cur); } } dataLength += outString(out, "\0", wide); outRepos(out, dataLength); pend = out->p; out->p = plen1; out_uint32_le(out, dataLength); out->p = plen2; out_uint32_le(out, dataLength); out->p = pend; outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } static MYPCSC_DWORD TS_SCardConnect(STREAM in, STREAM out, RD_BOOL wide) { MYPCSC_DWORD rv; SCARDCONTEXT myHContext; SERVER_SCARDCONTEXT hContext; char *szReader; SERVER_DWORD dwShareMode; SERVER_DWORD dwPreferredProtocol; MYPCSC_SCARDHANDLE myHCard; SERVER_SCARDHANDLE hCard; MYPCSC_DWORD dwActiveProtocol; PMEM_HANDLE lcHandle = NULL; in->p += 0x1C; in_uint32_le(in, dwShareMode); in_uint32_le(in, dwPreferredProtocol); inReaderName(&lcHandle, in, &szReader, wide); in->p += 0x04; in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardConnect(context: 0x%08x [0x%lx], share: 0x%08x, proto: 0x%08x, reader: \"%s\")\n", (unsigned) hContext, myHContext, (unsigned) dwShareMode, (unsigned) dwPreferredProtocol, szReader ? szReader : "NULL")); rv = SCardConnect(myHContext, szReader, (MYPCSC_DWORD) dwShareMode, (MYPCSC_DWORD) dwPreferredProtocol, &myHCard, &dwActiveProtocol); hCard = 0; if (myHCard) { _scard_handle_list_add(myHCard); hCard = _scard_handle_list_get_server_handle(myHCard); } if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { char *szVendor = getVendor(szReader); DEBUG_SCARD(("SCARD: -> Success (hcard: 0x%08x [0x%lx])\n", (unsigned) hCard, myHCard)); if (szVendor && (strlen(szVendor) > 0)) { DEBUG_SCARD(("SCARD: Set Attribute ATTR_VENDOR_NAME\n")); pthread_mutex_lock(&hcardAccess); PSCHCardRec hcard = xmalloc(sizeof(TSCHCardRec)); if (hcard) { hcard->hCard = hCard; hcard->vendor = szVendor; hcard->next = NULL; hcard->prev = NULL; if (hcardFirst) { hcardFirst->prev = hcard; hcard->next = hcardFirst; } hcardFirst = hcard; } pthread_mutex_unlock(&hcardAccess); } } out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000004); out_uint32_le(out, 0x016Cff34); /* if the active protocol > 4 billion, this is trouble. odds are low */ out_uint32_le(out, (SERVER_DWORD) dwActiveProtocol); out_uint32_le(out, 0x00000004); out_uint32_le(out, hCard); outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } static MYPCSC_DWORD TS_SCardReconnect(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; SERVER_SCARDHANDLE hCard; MYPCSC_SCARDHANDLE myHCard; SERVER_DWORD dwShareMode; SERVER_DWORD dwPreferredProtocol; SERVER_DWORD dwInitialization; MYPCSC_DWORD dwActiveProtocol; in->p += 0x20; in_uint32_le(in, dwShareMode); in_uint32_le(in, dwPreferredProtocol); in_uint32_le(in, dwInitialization); in->p += 0x04; in_uint32_le(in, hContext); in->p += 0x04; in_uint32_le(in, hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard); DEBUG_SCARD(("SCARD: SCardReconnect(context: 0x%08x, hcard: 0x%08x [%lx], share: 0x%08x, proto: 0x%08x, init: 0x%08x)\n", (unsigned) hContext, (unsigned) hCard, myHCard, (unsigned) dwShareMode, (unsigned) dwPreferredProtocol, (unsigned) dwInitialization)); rv = SCardReconnect(myHCard, (MYPCSC_DWORD) dwShareMode, (MYPCSC_DWORD) dwPreferredProtocol, (MYPCSC_DWORD) dwInitialization, &dwActiveProtocol); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success (proto: 0x%08x)\n", (unsigned) dwActiveProtocol)); } out_uint32_le(out, (SERVER_DWORD) dwActiveProtocol); outForceAlignment(out, 8); return rv; } static MYPCSC_DWORD TS_SCardDisconnect(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; SERVER_SCARDHANDLE hCard; MYPCSC_SCARDHANDLE myHCard; SERVER_DWORD dwDisposition; in->p += 0x20; in_uint32_le(in, dwDisposition); in->p += 0x04; in_uint32_le(in, hContext); in->p += 0x04; in_uint32_le(in, hCard); myHContext = _scard_handle_list_get_pcsc_handle(hContext); myHCard = _scard_handle_list_get_pcsc_handle(hCard); DEBUG_SCARD(("SCARD: SCardDisconnect(context: 0x%08x [0x%lx], hcard: 0x%08x [0x%lx], disposition: 0x%08x)\n", (unsigned) hContext, myHContext, (unsigned) hCard, myHCard, (unsigned) dwDisposition)); pthread_mutex_lock(&hcardAccess); PSCHCardRec hcard = hcardFirst; while (hcard) { if (hcard->hCard == hCard) { if (hcard->prev) hcard->prev->next = hcard->next; if (hcard->next) hcard->next->prev = hcard->prev; if (hcardFirst == hcard) hcardFirst = hcard->next; xfree(hcard); break; } hcard = hcard->next; } pthread_mutex_unlock(&hcardAccess); rv = SCardDisconnect(myHCard, (MYPCSC_DWORD) dwDisposition); _scard_handle_list_remove(myHCard); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success\n")); } outForceAlignment(out, 8); return rv; } /* Currently unused */ #if 0 static int needStatusRecheck(MYPCSC_DWORD rv, MYPCSC_LPSCARD_READERSTATE_A rsArray, SERVER_DWORD dwCount) { int i, recall = 0; if (rv == SCARD_S_SUCCESS) { MYPCSC_LPSCARD_READERSTATE_A cur; for (i = 0, cur = rsArray; i < dwCount; i++, cur++) { if (cur->dwEventState & SCARD_STATE_UNKNOWN) { cur->dwCurrentState = cur->dwEventState; recall++; } } } return recall; } static RD_BOOL mappedStatus(MYPCSC_DWORD code) { code >>= 16; code &= 0x0000FFFF; return (code % 2); } #endif static void copyReaderState_MyPCSCToServer(MYPCSC_LPSCARD_READERSTATE_A src, SERVER_LPSCARD_READERSTATE_A dst, MYPCSC_DWORD readerCount) { MYPCSC_LPSCARD_READERSTATE_A srcIter; SERVER_LPSCARD_READERSTATE_A dstIter; MYPCSC_DWORD i; for (i = 0, srcIter = src, dstIter = dst; i < readerCount; i++, srcIter++, dstIter++) { dstIter->szReader = srcIter->szReader; dstIter->pvUserData = srcIter->pvUserData; dstIter->dwCurrentState = srcIter->dwCurrentState; dstIter->dwEventState = srcIter->dwEventState; dstIter->cbAtr = srcIter->cbAtr; memcpy(dstIter->rgbAtr, srcIter->rgbAtr, MAX_ATR_SIZE * sizeof(unsigned char)); } } static void copyReaderState_ServerToMyPCSC(SERVER_LPSCARD_READERSTATE_A src, MYPCSC_LPSCARD_READERSTATE_A dst, SERVER_DWORD readerCount) { SERVER_LPSCARD_READERSTATE_A srcIter; MYPCSC_LPSCARD_READERSTATE_A dstIter; SERVER_DWORD i; for (i = 0, srcIter = src, dstIter = dst; i < readerCount; i++, srcIter++, dstIter++) { dstIter->szReader = srcIter->szReader; dstIter->pvUserData = srcIter->pvUserData; dstIter->dwCurrentState = srcIter->dwCurrentState; dstIter->dwEventState = srcIter->dwEventState; dstIter->cbAtr = srcIter->cbAtr; memcpy(dstIter->rgbAtr, srcIter->rgbAtr, MAX_ATR_SIZE * sizeof(unsigned char)); } } static MYPCSC_DWORD TS_SCardGetStatusChange(STREAM in, STREAM out, RD_BOOL wide) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; SERVER_DWORD dwTimeout; SERVER_DWORD dwCount; SERVER_DWORD dwPointerId; SERVER_LPSCARD_READERSTATE_A rsArray, cur; MYPCSC_LPSCARD_READERSTATE_A myRsArray; long i; PMEM_HANDLE lcHandle = NULL; in->p += 0x18; in_uint32_le(in, dwTimeout); in_uint32_le(in, dwCount); in->p += 0x08; in_uint32_le(in, hContext); in->p += 0x04; myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardGetStatusChange(context: 0x%08x [0x%lx], timeout: 0x%08x, count: %d)\n", (unsigned) hContext, myHContext, (unsigned) dwTimeout, (int) dwCount)); if (dwCount > 0) { rsArray = SC_xmalloc(&lcHandle, dwCount * sizeof(SERVER_SCARD_READERSTATE_A)); if (!rsArray) return SC_returnNoMemoryError(&lcHandle, in, out); memset(rsArray, 0, dwCount * sizeof(SERVER_SCARD_READERSTATE_A)); for (i = 0, cur = rsArray; i < dwCount; i++, cur++) { in_uint32_le(in, dwPointerId); cur->szReader = (char *) (intptr_t) dwPointerId; in_uint32_le(in, cur->dwCurrentState); in_uint32_le(in, cur->dwEventState); in_uint32_le(in, cur->cbAtr); in_uint8a(in, cur->rgbAtr, sizeof(cur->rgbAtr)); } for (i = 0, cur = rsArray; i < dwCount; i++, cur++) { if (cur->szReader != NULL) { SERVER_DWORD dataLength; in->p += 0x08; in_uint32_le(in, dataLength); inRepos(in, inString(&lcHandle, in, (char **) &(cur->szReader), dataLength, wide)); if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0) cur->dwCurrentState |= SCARD_STATE_IGNORE; } DEBUG_SCARD(("SCARD: \"%s\"\n", cur->szReader ? cur->szReader : "NULL")); DEBUG_SCARD(("SCARD: user: %p, state: 0x%08x, event: 0x%08x\n", cur->pvUserData, (unsigned) cur->dwCurrentState, (unsigned) cur->dwEventState)); } } else { rsArray = NULL; } myRsArray = SC_xmalloc(&lcHandle, dwCount * sizeof(MYPCSC_SCARD_READERSTATE_A)); if (!myRsArray) return SC_returnNoMemoryError(&lcHandle, in, out); memset(myRsArray, 0, dwCount * sizeof(SERVER_SCARD_READERSTATE_A)); copyReaderState_ServerToMyPCSC(rsArray, myRsArray, (SERVER_DWORD) dwCount); /* Workaround for a bug in pcsclite, timeout value of 0 is handled as INFINIT but is by Windows PCSC spec. used for polling current state. */ if (dwTimeout == 0) dwTimeout = 1; rv = SCardGetStatusChange(myHContext, (MYPCSC_DWORD) dwTimeout, myRsArray, (MYPCSC_DWORD) dwCount); copyReaderState_MyPCSCToServer(myRsArray, rsArray, (MYPCSC_DWORD) dwCount); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success\n")); } out_uint32_le(out, dwCount); out_uint32_le(out, 0x00084dd8); out_uint32_le(out, dwCount); for (i = 0, cur = rsArray; i < dwCount; i++, cur++) { DEBUG_SCARD(("SCARD: \"%s\"\n", cur->szReader ? cur->szReader : "NULL")); DEBUG_SCARD(("SCARD: user: %p, state: 0x%08x, event: 0x%08x\n", cur->pvUserData, (unsigned) cur->dwCurrentState, (unsigned) cur->dwEventState)); /* Do endian swaps... */ cur->dwCurrentState = swap32(cur->dwCurrentState); cur->dwEventState = swap32(cur->dwEventState); cur->cbAtr = swap32(cur->cbAtr); out_uint8p(out, (void *) ((unsigned char **) cur + 2), sizeof(SERVER_SCARD_READERSTATE_A) - 2 * sizeof(unsigned char *)); } outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } static MYPCSC_DWORD TS_SCardCancel(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; in->p += 0x1C; in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardCancel(context: 0x%08x [0x%08lx])\n", (unsigned) hContext, (unsigned long) myHContext)); rv = SCardCancel(myHContext); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success\n")); } outForceAlignment(out, 8); return rv; } static MYPCSC_DWORD TS_SCardLocateCardsByATR(STREAM in, STREAM out, RD_BOOL wide) { int i, j, k; MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; /* The SCARD_ATRMASK_L struct doesn't contain any longs or DWORDs - no need to split into SERVER_ and MYPCSC_ */ LPSCARD_ATRMASK_L pAtrMasks, cur; SERVER_DWORD atrMaskCount = 0; SERVER_DWORD readerCount = 0; SERVER_LPSCARD_READERSTATE_A rsArray, ResArray, rsCur; MYPCSC_LPSCARD_READERSTATE_A myRsArray; PMEM_HANDLE lcHandle = NULL; in->p += 0x2C; in_uint32_le(in, hContext); in_uint32_le(in, atrMaskCount); pAtrMasks = SC_xmalloc(&lcHandle, atrMaskCount * sizeof(SCARD_ATRMASK_L)); if (!pAtrMasks) return SC_returnNoMemoryError(&lcHandle, in, out); in_uint8a(in, pAtrMasks, atrMaskCount * sizeof(SCARD_ATRMASK_L)); in_uint32_le(in, readerCount); rsArray = SC_xmalloc(&lcHandle, readerCount * sizeof(SCARD_READERSTATE)); if (!rsArray) return SC_returnNoMemoryError(&lcHandle, in, out); memset(rsArray, 0, readerCount * sizeof(SCARD_READERSTATE)); myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardLocateCardsByATR(context: 0x%08x [0x%08lx], atrs: %d, readers: %d)\n", (unsigned) hContext, (unsigned long) myHContext, (int) atrMaskCount, (int) readerCount)); for (i = 0, cur = pAtrMasks; i < atrMaskCount; i++, cur++) { cur->cbAtr = swap32(cur->cbAtr); DEBUG_SCARD(("SCARD: ATR: ")); for (j = 0; j < pAtrMasks->cbAtr; j++) { DEBUG_SCARD(("%02x%c", (unsigned) (unsigned char) cur->rgbAtr[j], (j == pAtrMasks->cbAtr - 1) ? ' ' : ':'))} DEBUG_SCARD(("\n")); DEBUG_SCARD(("SCARD: ")); for (j = 0; j < pAtrMasks->cbAtr; j++) { DEBUG_SCARD(("%02x%c", (unsigned) (unsigned char) cur->rgbMask[j], (j == pAtrMasks->cbAtr - 1) ? ' ' : ':'))} DEBUG_SCARD(("\n")); } for (i = 0, rsCur = (SERVER_LPSCARD_READERSTATE_A) ((unsigned char **) rsArray + 2); i < readerCount; i++, rsCur++) { in_uint8s(in, 4); in_uint8a(in, rsCur, SERVER_SCARDSTATESIZE); } ResArray = SC_xmalloc(&lcHandle, readerCount * sizeof(SERVER_SCARD_READERSTATE_A)); if (!ResArray) return SC_returnNoMemoryError(&lcHandle, in, out); for (i = 0, rsCur = rsArray; i < readerCount; i++, rsCur++) { /* Do endian swaps... */ rsCur->dwCurrentState = swap32(rsCur->dwCurrentState); rsCur->dwEventState = swap32(rsCur->dwEventState); rsCur->cbAtr = swap32(rsCur->cbAtr); inReaderName(&lcHandle, in, (char **) &rsCur->szReader, wide); DEBUG_SCARD(("SCARD: \"%s\"\n", rsCur->szReader ? rsCur->szReader : "NULL")); DEBUG_SCARD(("SCARD: user: %p, state: 0x%08x, event: 0x%08x\n", rsCur->pvUserData, (unsigned) rsCur->dwCurrentState, (unsigned) rsCur->dwEventState)); } memcpy(ResArray, rsArray, readerCount * sizeof(SERVER_SCARD_READERSTATE_A)); /* FIXME segfault here. */ myRsArray = SC_xmalloc(&lcHandle, readerCount * sizeof(MYPCSC_SCARD_READERSTATE_A)); if (!myRsArray) return SC_returnNoMemoryError(&lcHandle, in, out); copyReaderState_ServerToMyPCSC(rsArray, myRsArray, readerCount); rv = SCardGetStatusChange(myHContext, 0x00000001, myRsArray, readerCount); copyReaderState_MyPCSCToServer(myRsArray, rsArray, readerCount); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success\n")); cur = pAtrMasks; for (i = 0, cur = pAtrMasks; i < atrMaskCount; i++, cur++) { for (j = 0, rsCur = rsArray; j < readerCount; j++, rsCur++) { RD_BOOL equal = 1; for (k = 0; k < cur->cbAtr; k++) { if ((cur->rgbAtr[k] & cur->rgbMask[k]) != (rsCur->rgbAtr[k] & cur->rgbMask[k])) { equal = 0; break; } } if (equal) { rsCur->dwEventState |= 0x00000040; /* SCARD_STATE_ATRMATCH 0x00000040 */ memcpy(ResArray + j, rsCur, sizeof(SCARD_READERSTATE)); DEBUG_SCARD(("SCARD: \"%s\"\n", rsCur->szReader ? rsCur->szReader : "NULL")); DEBUG_SCARD(("SCARD: user: %p, state: 0x%08x, event: 0x%08x\n", rsCur->pvUserData, (unsigned) rsCur->dwCurrentState, (unsigned) rsCur->dwEventState)); } } } } out_uint32_le(out, readerCount); out_uint32_le(out, 0x00084dd8); out_uint32_le(out, readerCount); for (i = 0, rsCur = ResArray; i < readerCount; i++, rsCur++) { /* Do endian swaps... */ rsCur->dwCurrentState = swap32(rsCur->dwCurrentState); rsCur->dwEventState = swap32(rsCur->dwEventState); rsCur->cbAtr = swap32(rsCur->cbAtr); out_uint8p(out, (void *) ((unsigned char **) rsCur + 2), sizeof(SCARD_READERSTATE) - 2 * sizeof(unsigned char *)); } outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } static DWORD TS_SCardBeginTransaction(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hCard; MYPCSC_SCARDCONTEXT myHCard; in->p += 0x30; in_uint32_le(in, hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard); DEBUG_SCARD(("SCARD: SCardBeginTransaction(hcard: 0x%08x [0x%lx])\n", (unsigned) hCard, myHCard)); rv = SCardBeginTransaction(myHCard); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success\n")); } outForceAlignment(out, 8); return rv; } static DWORD TS_SCardEndTransaction(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hCard; MYPCSC_SCARDCONTEXT myHCard; SERVER_DWORD dwDisposition = 0; in->p += 0x20; in_uint32_le(in, dwDisposition); in->p += 0x0C; in_uint32_le(in, hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard); DEBUG_SCARD(("SCARD: SCardEndTransaction(hcard: 0x%08x [0x%lx], disposition: 0x%08x)\n", (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwDisposition)); rv = SCardEndTransaction(myHCard, (MYPCSC_DWORD) dwDisposition); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success\n")); } outForceAlignment(out, 8); return rv; } static void copyIORequest_MyPCSCToServer(MYPCSC_LPSCARD_IO_REQUEST src, SERVER_LPSCARD_IO_REQUEST dst) { unsigned char *srcBytes, *dstBytes; size_t bytesToCopy = src->cbPciLength - sizeof(MYPCSC_SCARD_IO_REQUEST); srcBytes = ((unsigned char *) src + sizeof(MYPCSC_SCARD_IO_REQUEST)); dstBytes = ((unsigned char *) dst + sizeof(SERVER_SCARD_IO_REQUEST)); dst->dwProtocol = swap32((uint32_t) src->dwProtocol); dst->cbPciLength = swap32((uint32_t) src->cbPciLength - sizeof(MYPCSC_SCARD_IO_REQUEST) + sizeof(SERVER_SCARD_IO_REQUEST)); memcpy(dstBytes, srcBytes, bytesToCopy); } static void copyIORequest_ServerToMyPCSC(SERVER_LPSCARD_IO_REQUEST src, MYPCSC_LPSCARD_IO_REQUEST dst) { unsigned char *srcBytes, *dstBytes; size_t bytesToCopy = src->cbPciLength - sizeof(SERVER_SCARD_IO_REQUEST); srcBytes = ((unsigned char *) src + sizeof(SERVER_SCARD_IO_REQUEST)); dstBytes = ((unsigned char *) dst + sizeof(MYPCSC_SCARD_IO_REQUEST)); dst->dwProtocol = swap32(src->dwProtocol); dst->cbPciLength = src->cbPciLength /* already correct endian */ - sizeof(SERVER_SCARD_IO_REQUEST) + sizeof(MYPCSC_SCARD_IO_REQUEST); memcpy(dstBytes, srcBytes, bytesToCopy); } static DWORD TS_SCardTransmit(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_DWORD map[7], linkedLen; void *tmp; SERVER_SCARDCONTEXT hCard; MYPCSC_SCARDCONTEXT myHCard; SERVER_LPSCARD_IO_REQUEST pioSendPci, pioRecvPci; MYPCSC_LPSCARD_IO_REQUEST myPioSendPci, myPioRecvPci; unsigned char *sendBuf = NULL, *recvBuf = NULL; SERVER_DWORD cbSendLength, cbRecvLength; MYPCSC_DWORD myCbRecvLength; PMEM_HANDLE lcHandle = NULL; in->p += 0x14; in_uint32_le(in, map[0]); in->p += 0x04; in_uint32_le(in, map[1]); pioSendPci = SC_xmalloc(&lcHandle, sizeof(SERVER_SCARD_IO_REQUEST)); if (!pioSendPci) return SC_returnNoMemoryError(&lcHandle, in, out); in_uint8a(in, pioSendPci, sizeof(SERVER_SCARD_IO_REQUEST)); in_uint32_le(in, map[2]); in_uint32_le(in, cbSendLength); in_uint32_le(in, map[3]); in_uint32_le(in, map[4]); in_uint32_le(in, map[5]); in_uint32_le(in, cbRecvLength); if (map[0] & INPUT_LINKED) inSkipLinked(in); in->p += 0x04; in_uint32_le(in, hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard); if (map[2] & INPUT_LINKED) { in_uint32_le(in, linkedLen); pioSendPci->cbPciLength = linkedLen + sizeof(SERVER_SCARD_IO_REQUEST); tmp = SC_xmalloc(&lcHandle, pioSendPci->cbPciLength); if (!tmp) return SC_returnNoMemoryError(&lcHandle, in, out); in_uint8a(in, (void *) ((unsigned char *) tmp + sizeof(SERVER_SCARD_IO_REQUEST)), linkedLen); memcpy(tmp, pioSendPci, sizeof(SERVER_SCARD_IO_REQUEST)); SC_xfree(&lcHandle, pioSendPci); pioSendPci = tmp; tmp = NULL; } else pioSendPci->cbPciLength = sizeof(SERVER_SCARD_IO_REQUEST); if (map[3] & INPUT_LINKED) { in_uint32_le(in, linkedLen); sendBuf = SC_xmalloc(&lcHandle, linkedLen); if (!sendBuf) return SC_returnNoMemoryError(&lcHandle, in, out); in_uint8a(in, sendBuf, linkedLen); inRepos(in, linkedLen); } else sendBuf = NULL; if (cbRecvLength) { recvBuf = SC_xmalloc(&lcHandle, cbRecvLength); if (!recvBuf) return SC_returnNoMemoryError(&lcHandle, in, out); } if (map[4] & INPUT_LINKED) { pioRecvPci = SC_xmalloc(&lcHandle, sizeof(SERVER_SCARD_IO_REQUEST)); if (!pioRecvPci) return SC_returnNoMemoryError(&lcHandle, in, out); in_uint8a(in, pioRecvPci, sizeof(SERVER_SCARD_IO_REQUEST)); in_uint32_le(in, map[6]); if (map[6] & INPUT_LINKED) { in_uint32_le(in, linkedLen); pioRecvPci->cbPciLength = linkedLen + sizeof(SERVER_SCARD_IO_REQUEST); tmp = SC_xmalloc(&lcHandle, pioRecvPci->cbPciLength); if (!tmp) return SC_returnNoMemoryError(&lcHandle, in, out); in_uint8a(in, (void *) ((unsigned char *) tmp + sizeof(SERVER_SCARD_IO_REQUEST)), linkedLen); memcpy(tmp, pioRecvPci, sizeof(SERVER_SCARD_IO_REQUEST)); SC_xfree(&lcHandle, pioRecvPci); pioRecvPci = tmp; tmp = NULL; } else pioRecvPci->cbPciLength = sizeof(SERVER_SCARD_IO_REQUEST); } else pioRecvPci = NULL; DEBUG_SCARD(("SCARD: SCardTransmit(hcard: 0x%08x [0x%08lx], send: %d bytes, recv: %d bytes)\n", (unsigned) hCard, (unsigned long) myHCard, (int) cbSendLength, (int) cbRecvLength)); myCbRecvLength = cbRecvLength; myPioSendPci = SC_xmalloc(&lcHandle, sizeof(MYPCSC_SCARD_IO_REQUEST) + pioSendPci->cbPciLength - sizeof(SERVER_SCARD_IO_REQUEST)); if (!myPioSendPci) return SC_returnNoMemoryError(&lcHandle, in, out); copyIORequest_ServerToMyPCSC(pioSendPci, myPioSendPci); /* always a send, not always a recv */ if (pioRecvPci) { myPioRecvPci = SC_xmalloc(&lcHandle, sizeof(MYPCSC_SCARD_IO_REQUEST) + pioRecvPci->cbPciLength - sizeof(SERVER_SCARD_IO_REQUEST)); if (!myPioRecvPci) return SC_returnNoMemoryError(&lcHandle, in, out); copyIORequest_ServerToMyPCSC(pioRecvPci, myPioRecvPci); } else { myPioRecvPci = NULL; } rv = SCardTransmit(myHCard, myPioSendPci, sendBuf, (MYPCSC_DWORD) cbSendLength, myPioRecvPci, recvBuf, &myCbRecvLength); cbRecvLength = myCbRecvLength; /* FIXME: handle responses with length > 448 bytes */ if (cbRecvLength > 448) { warning("Card response limited from %d to 448 bytes!\n", cbRecvLength); DEBUG_SCARD(("SCARD: Truncated %d to %d\n", (unsigned int) cbRecvLength, 448)); cbRecvLength = 448; } if (pioRecvPci) { /* * pscs-lite mishandles this structure in some cases. * make sure we only copy it if it is valid. */ if (myPioRecvPci->cbPciLength >= sizeof(MYPCSC_SCARD_IO_REQUEST)) copyIORequest_MyPCSCToServer(myPioRecvPci, pioRecvPci); } if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success (%d bytes)\n", (int) cbRecvLength)); #if 0 if ((pioRecvPci != NULL) && (mypioRecvPci->cbPciLength > 0)) { out_uint32_le(out, (DWORD) pioRecvPci); /* if not NULL, this 4 bytes indicates that pioRecvPci is present */ } else #endif out_uint32_le(out, 0); /* pioRecvPci 0x00; */ outBufferStart(out, cbRecvLength); /* start of recvBuf output */ #if 0 if ((pioRecvPci) && (mypioRecvPci->cbPciLength > 0)) { out_uint32_le(out, mypioRecvPci->dwProtocol); int len = mypioRecvPci->cbPciLength - sizeof(mypioRecvPci); outBufferStartWithLimit(out, len, 12); outBufferFinishWithLimit(out, (char *) ((DWORD) pioRecvPci + sizeof(pioRecvPci)), len, 12); } #endif outBufferFinish(out, (char *) recvBuf, cbRecvLength); } outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } static MYPCSC_DWORD TS_SCardStatus(STREAM in, STREAM out, RD_BOOL wide) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hCard; MYPCSC_SCARDCONTEXT myHCard; SERVER_DWORD dwState = 0, dwProtocol = 0, dwReaderLen, dwAtrLen; MYPCSC_DWORD state, protocol, readerLen, atrLen; SERVER_DWORD dataLength; PMEM_HANDLE lcHandle = NULL; char *readerName; unsigned char *atr; in->p += 0x24; in_uint32_le(in, dwReaderLen); in_uint32_le(in, dwAtrLen); in->p += 0x0C; in_uint32_le(in, hCard); in->p += 0x04; myHCard = _scard_handle_list_get_pcsc_handle(hCard); DEBUG_SCARD(("SCARD: SCardStatus(hcard: 0x%08x [0x%08lx], reader len: %d bytes, atr len: %d bytes)\n", (unsigned) hCard, (unsigned long) myHCard, (int) dwReaderLen, (int) dwAtrLen)); if (dwReaderLen <= 0 || dwReaderLen == SCARD_AUTOALLOCATE || dwReaderLen > SCARD_MAX_MEM) dwReaderLen = SCARD_MAX_MEM; if (dwAtrLen <= 0 || dwAtrLen == SCARD_AUTOALLOCATE || dwAtrLen > SCARD_MAX_MEM) dwAtrLen = SCARD_MAX_MEM; #if 1 /* * Active client sometimes sends a readerlen *just* big enough * SCardStatus doesn't seem to like this. This is a workaround, * aka hack! */ dwReaderLen = 200; #endif readerName = SC_xmalloc(&lcHandle, dwReaderLen + 2); if (!readerName) return SC_returnNoMemoryError(&lcHandle, in, out); atr = SC_xmalloc(&lcHandle, dwAtrLen + 1); if (!atr) return SC_returnNoMemoryError(&lcHandle, in, out); state = dwState; protocol = dwProtocol; readerLen = dwReaderLen; atrLen = dwAtrLen; rv = SCardStatus(myHCard, readerName, &readerLen, &state, &protocol, atr, &atrLen); dwAtrLen = atrLen; dwReaderLen = readerLen; dwProtocol = protocol; dwState = state; if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); return SC_returnCode(rv, &lcHandle, in, out); } else { int i; DEBUG_SCARD(("SCARD: -> Success (state: 0x%08x, proto: 0x%08x)\n", (unsigned) dwState, (unsigned) dwProtocol)); DEBUG_SCARD(("SCARD: Reader: \"%s\"\n", readerName ? readerName : "NULL")); DEBUG_SCARD(("SCARD: ATR: ")); for (i = 0; i < dwAtrLen; i++) { DEBUG_SCARD(("%02x%c", atr[i], (i == dwAtrLen - 1) ? ' ' : ':')); } DEBUG_SCARD(("\n")); if (dwState & (SCARD_SPECIFIC | SCARD_NEGOTIABLE)) dwState = 0x00000006; else #if 0 if (dwState & SCARD_SPECIFIC) dwState = 0x00000006; else if (dwState & SCARD_NEGOTIABLE) dwState = 0x00000005; else #endif if (dwState & SCARD_POWERED) dwState = 0x00000004; else if (dwState & SCARD_SWALLOWED) dwState = 0x00000003; else if (dwState & SCARD_PRESENT) dwState = 0x00000002; else if (dwState & SCARD_ABSENT) dwState = 0x00000001; else dwState = 0x00000000; void *p_len1 = out->p; out_uint32_le(out, dwReaderLen); out_uint32_le(out, 0x00020000); out_uint32_le(out, dwState); out_uint32_le(out, dwProtocol); out_uint8p(out, atr, dwAtrLen); if (dwAtrLen < 32) { out_uint8s(out, 32 - dwAtrLen); } out_uint32_le(out, dwAtrLen); void *p_len2 = out->p; out_uint32_le(out, dwReaderLen); dataLength = outString(out, readerName, wide); dataLength += outString(out, "\0", wide); outRepos(out, dataLength); void *psave = out->p; out->p = p_len1; out_uint32_le(out, dataLength); out->p = p_len2; out_uint32_le(out, dataLength); out->p = psave; } outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } static MYPCSC_DWORD TS_SCardState(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hCard; MYPCSC_SCARDCONTEXT myHCard; SERVER_DWORD dwState = 0, dwProtocol = 0, dwReaderLen, dwAtrLen; MYPCSC_DWORD state, protocol, readerLen, atrLen; PMEM_HANDLE lcHandle = NULL; char *readerName; unsigned char *atr; in->p += 0x24; in_uint32_le(in, dwAtrLen); in->p += 0x0C; in_uint32_le(in, hCard); in->p += 0x04; myHCard = _scard_handle_list_get_pcsc_handle(hCard); DEBUG_SCARD(("SCARD: SCardState(hcard: 0x%08x [0x%08lx], atr len: %d bytes)\n", (unsigned) hCard, (unsigned long) myHCard, (int) dwAtrLen)); dwReaderLen = SCARD_MAX_MEM; if (dwAtrLen <= 0 || dwAtrLen == SCARD_AUTOALLOCATE || dwAtrLen > SCARD_MAX_MEM) dwAtrLen = SCARD_MAX_MEM; readerName = SC_xmalloc(&lcHandle, dwReaderLen + 2); if (!readerName) return SC_returnNoMemoryError(&lcHandle, in, out); atr = SC_xmalloc(&lcHandle, dwAtrLen + 1); if (!atr) return SC_returnNoMemoryError(&lcHandle, in, out); state = dwState; protocol = dwProtocol; readerLen = dwReaderLen; atrLen = dwAtrLen; rv = SCardStatus(myHCard, readerName, &readerLen, &state, &protocol, atr, &atrLen); dwAtrLen = atrLen; dwReaderLen = readerLen; dwProtocol = protocol; dwState = state; if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); return SC_returnCode(rv, &lcHandle, in, out); } else { int i; DEBUG_SCARD(("SCARD: -> Success (state: 0x%08x, proto: 0x%08x)\n", (unsigned) dwState, (unsigned) dwProtocol)); DEBUG_SCARD(("SCARD: ATR: ")); for (i = 0; i < dwAtrLen; i++) { DEBUG_SCARD(("%02x%c", atr[i], (i == dwAtrLen - 1) ? ' ' : ':')); } DEBUG_SCARD(("\n")); if (dwState & (SCARD_SPECIFIC | SCARD_NEGOTIABLE)) dwState = 0x00000006; else #if 0 if (dwState & SCARD_SPECIFIC) dwState = 0x00000006; else if (dwState & SCARD_NEGOTIABLE) dwState = 0x00000005; else #endif if (dwState & SCARD_POWERED) dwState = 0x00000004; else if (dwState & SCARD_SWALLOWED) dwState = 0x00000003; else if (dwState & SCARD_PRESENT) dwState = 0x00000002; else if (dwState & SCARD_ABSENT) dwState = 0x00000001; else dwState = 0x00000000; out_uint32_le(out, dwState); out_uint32_le(out, dwProtocol); out_uint32_le(out, dwAtrLen); out_uint32_le(out, 0x00000001); out_uint32_le(out, dwAtrLen); out_uint8p(out, atr, dwAtrLen); outRepos(out, dwAtrLen); } outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } #ifndef WITH_PCSC120 /* Currently unused */ #if 0 static MYPCSC_DWORD TS_SCardListReaderGroups(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; SERVER_DWORD dwGroups; MYPCSC_DWORD groups; char *szGroups; PMEM_HANDLE lcHandle = NULL; in->p += 0x20; in_uint32_le(in, dwGroups); in->p += 0x04; in_uint32_le(in, hContext); myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardListReaderGroups(context: 0x%08x [0x%08lx], groups: %d)\n", (unsigned) hContext, (unsigned int) myHContext, (int) dwGroups)); if (dwGroups <= 0 || dwGroups == SCARD_AUTOALLOCATE || dwGroups > SCARD_MAX_MEM) dwGroups = SCARD_MAX_MEM; szGroups = SC_xmalloc(&lcHandle, dwGroups); if (!szGroups) return SC_returnNoMemoryError(&lcHandle, in, out); groups = dwGroups; rv = SCardListReaderGroups(myHContext, szGroups, &groups); dwGroups = groups; if (rv) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); return SC_returnCode(rv, &lcHandle, in, out); } else { int i; char *cur; DEBUG_SCARD(("SCARD: -> Success\n")); for (i = 0, cur = szGroups; i < dwGroups; i++, cur += strlen(cur) + 1) { DEBUG_SCARD(("SCARD: %s\n", cur)); } } out_uint32_le(out, dwGroups); out_uint32_le(out, 0x00200000); out_uint32_le(out, dwGroups); out_uint8a(out, szGroups, dwGroups); outRepos(out, dwGroups); out_uint32_le(out, 0x00000000); outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } #endif static MYPCSC_DWORD TS_SCardGetAttrib(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hCard; MYPCSC_SCARDCONTEXT myHCard; SERVER_DWORD dwAttrId, dwAttrLen; MYPCSC_DWORD attrLen; unsigned char *pbAttr; PMEM_HANDLE lcHandle = NULL; in->p += 0x20; in_uint32_le(in, dwAttrId); in->p += 0x04; in_uint32_le(in, dwAttrLen); in->p += 0x0C; in_uint32_le(in, hCard); myHCard = _scard_handle_list_get_pcsc_handle(hCard); DEBUG_SCARD(("SCARD: SCardGetAttrib(hcard: 0x%08x [0x%08lx], attrib: 0x%08x (%d bytes))\n", (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwAttrId, (int) dwAttrLen)); if (dwAttrLen > MAX_BUFFER_SIZE) dwAttrLen = MAX_BUFFER_SIZE; if (dwAttrLen > SCARD_AUTOALLOCATE) pbAttr = NULL; else if ((dwAttrLen < 0) || (dwAttrLen > SCARD_MAX_MEM)) { dwAttrLen = (SERVER_DWORD) SCARD_AUTOALLOCATE; pbAttr = NULL; } else { pbAttr = SC_xmalloc(&lcHandle, dwAttrLen); if (!pbAttr) return SC_returnNoMemoryError(&lcHandle, in, out); } attrLen = dwAttrLen; rv = SCardGetAttrib(myHCard, (MYPCSC_DWORD) dwAttrId, pbAttr, &attrLen); dwAttrLen = attrLen; if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); return SC_returnCode(rv, &lcHandle, in, out); } else { DEBUG_SCARD(("SCARD: -> Success (%d bytes)\n", (int) dwAttrLen)); out_uint32_le(out, dwAttrLen); out_uint32_le(out, 0x00000200); out_uint32_le(out, dwAttrLen); if (!pbAttr) { out_uint8s(out, dwAttrLen); } else { out_uint8p(out, pbAttr, dwAttrLen); } outRepos(out, dwAttrLen); out_uint32_le(out, 0x00000000); } outForceAlignment(out, 8); return rv; } /* Currently unused */ #if 0 static MYPCSC_DWORD TS_SCardSetAttrib(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hCard; MYPCSC_SCARDCONTEXT myHCard; SERVER_DWORD dwAttrId; SERVER_DWORD dwAttrLen; unsigned char *pbAttr; PMEM_HANDLE lcHandle = NULL; in->p += 0x20; in_uint32_le(in, dwAttrId); in->p += 0x04; in_uint32_le(in, dwAttrLen); in->p += 0x0C; in_uint32_le(in, hCard); myHCard = scHandleToMyPCSC(hCard); DEBUG_SCARD(("SCARD: SCardSetAttrib(hcard: 0x%08x [0x%08lx], attrib: 0x%08x (%d bytes))\n", (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwAttrId, (int) dwAttrLen)); if (dwAttrLen > MAX_BUFFER_SIZE) dwAttrLen = MAX_BUFFER_SIZE; pbAttr = SC_xmalloc(&lcHandle, dwAttrLen); if (!pbAttr) return SC_returnNoMemoryError(&lcHandle, in, out); in_uint8a(in, pbAttr, dwAttrLen); rv = SCardSetAttrib(myHCard, (MYPCSC_DWORD) dwAttrId, pbAttr, (MYPCSC_DWORD) dwAttrLen); if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success\n")); } out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000200); out_uint32_le(out, 0x00000000); out_uint32_le(out, 0x00000000); outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } #endif #endif static MYPCSC_DWORD TS_SCardControl(STREAM in, STREAM out) { MYPCSC_DWORD rv; SERVER_SCARDCONTEXT hContext; MYPCSC_SCARDCONTEXT myHContext; SERVER_SCARDHANDLE hCard; MYPCSC_SCARDHANDLE myHCard; SERVER_DWORD map[3]; SERVER_DWORD dwControlCode; unsigned char *pInBuffer, *pOutBuffer; SERVER_DWORD nInBufferSize, nOutBufferSize, nOutBufferRealSize, nBytesReturned; MYPCSC_DWORD sc_nBytesReturned; PMEM_HANDLE lcHandle = NULL; pInBuffer = NULL; pOutBuffer = NULL; in->p += 0x14; in_uint32_le(in, map[0]); in->p += 0x04; in_uint32_le(in, map[1]); in_uint32_le(in, dwControlCode); in_uint32_le(in, nInBufferSize); in_uint32_le(in, map[2]); in->p += 0x04; in_uint32_le(in, nOutBufferSize); in->p += 0x04; in_uint32_le(in, hContext); in->p += 0x04; in_uint32_le(in, hCard); if (map[2] & INPUT_LINKED) { /* read real input size */ in_uint32_le(in, nInBufferSize); if (nInBufferSize > 0) { pInBuffer = SC_xmalloc(&lcHandle, nInBufferSize); if (!pInBuffer) return SC_returnNoMemoryError(&lcHandle, in, out); in_uint8a(in, pInBuffer, nInBufferSize); } } myHCard = _scard_handle_list_get_pcsc_handle(hCard); myHContext = _scard_handle_list_get_pcsc_handle(hContext); DEBUG_SCARD(("SCARD: SCardControl(context: 0x%08x [0x%08lx], hcard: 0x%08x [0x%08lx], code: 0x%08x, in: %d bytes, out: %d bytes)\n", (unsigned) hContext, (unsigned long) myHContext, (unsigned) hCard, (unsigned long) myHCard, (unsigned) dwControlCode, (int) nInBufferSize, (int) nOutBufferSize)); /* Is this a proper Windows smart card ioctl? */ if ((dwControlCode & 0xffff0000) == (49 << 16)) { /* Translate to local encoding */ dwControlCode = (dwControlCode & 0x3ffc) >> 2; dwControlCode = SCARD_CTL_CODE(dwControlCode); } else { warning("Bogus smart card control code 0x%08x\n", dwControlCode); } #if 0 if (nOutBufferSize > 0) { nOutBufferRealSize = nOutBufferSize; } else #endif nOutBufferRealSize = 1024; nBytesReturned = nOutBufferRealSize; nBytesReturned = nOutBufferRealSize; pOutBuffer = SC_xmalloc(&lcHandle, nOutBufferRealSize); if (!pOutBuffer) return SC_returnNoMemoryError(&lcHandle, in, out); sc_nBytesReturned = nBytesReturned; #ifdef WITH_PCSC120 rv = SCardControl(myHCard, pInBuffer, (MYPCSC_DWORD) nInBufferSize, pOutBuffer, &sc_nBytesReturned); #else rv = SCardControl(myHCard, (MYPCSC_DWORD) dwControlCode, pInBuffer, (MYPCSC_DWORD) nInBufferSize, pOutBuffer, (MYPCSC_DWORD) nOutBufferRealSize, &sc_nBytesReturned); #endif nBytesReturned = sc_nBytesReturned; if (rv != SCARD_S_SUCCESS) { DEBUG_SCARD(("SCARD: -> Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned int) rv)); } else { DEBUG_SCARD(("SCARD: -> Success (out: %d bytes)\n", (int) nBytesReturned)); } #ifdef PCSCLITE_VERSION_NUMBER if (dwControlCode == SCARD_CTL_CODE(3400)) { int i; SERVER_DWORD cc; for (i = 0; i < nBytesReturned / 6; i++) { memcpy(&cc, pOutBuffer + 2 + i * 6, 4); cc = ntohl(cc); cc = cc - 0x42000000; cc = (49 << 16) | (cc << 2); cc = htonl(cc); memcpy(pOutBuffer + 2 + i * 6, &cc, 4); } } #endif out_uint32_le(out, nBytesReturned); out_uint32_le(out, 0x00000004); out_uint32_le(out, nBytesReturned); if (nBytesReturned > 0) { out_uint8p(out, pOutBuffer, nBytesReturned); outRepos(out, nBytesReturned); } outForceAlignment(out, 8); SC_xfreeallmemory(&lcHandle); return rv; } static MYPCSC_DWORD TS_SCardAccessStartedEvent(STREAM in, STREAM out) { DEBUG_SCARD(("SCARD: SCardAccessStartedEvent()\n")); out_uint8s(out, 8); return SCARD_S_SUCCESS; } static RD_NTSTATUS scard_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) { SERVER_DWORD Result = 0x00000000; unsigned char *psize, *pend, *pStatusCode; SERVER_DWORD addToEnd = 0; /* Processing request */ out_uint32_le(out, 0x00081001); /* Header lines */ out_uint32_le(out, 0xCCCCCCCC); psize = out->p; out_uint32_le(out, 0x00000000); /* Size of data portion */ out_uint32_le(out, 0x00000000); /* Zero bytes (may be usefull) */ pStatusCode = out->p; out_uint32_le(out, 0x00000000); /* Status Code */ switch (request) { /* SCardEstablishContext */ case SC_ESTABLISH_CONTEXT: { Result = (SERVER_DWORD) TS_SCardEstablishContext(in, out); break; } /* SCardReleaseContext */ case SC_RELEASE_CONTEXT: { Result = (SERVER_DWORD) TS_SCardReleaseContext(in, out); break; } /* SCardIsValidContext */ case SC_IS_VALID_CONTEXT: { Result = (SERVER_DWORD) TS_SCardIsValidContext(in, out); break; } /* SCardListReaders */ case SC_LIST_READERS: /* SCardListReadersA */ case SC_LIST_READERS + 4: /* SCardListReadersW */ { RD_BOOL wide = request != SC_LIST_READERS; Result = (SERVER_DWORD) TS_SCardListReaders(in, out, wide); break; } /* ScardConnect */ case SC_CONNECT: /* ScardConnectA */ case SC_CONNECT + 4: /* SCardConnectW */ { RD_BOOL wide = request != SC_CONNECT; Result = (SERVER_DWORD) TS_SCardConnect(in, out, wide); break; } /* ScardReconnect */ case SC_RECONNECT: { Result = (SERVER_DWORD) TS_SCardReconnect(in, out); break; } /* ScardDisconnect */ case SC_DISCONNECT: { Result = (SERVER_DWORD) TS_SCardDisconnect(in, out); break; } /* ScardGetStatusChange */ case SC_GET_STATUS_CHANGE: /* SCardGetStatusChangeA */ case SC_GET_STATUS_CHANGE + 4: /* SCardGetStatusChangeW */ { RD_BOOL wide = request != SC_GET_STATUS_CHANGE; Result = (SERVER_DWORD) TS_SCardGetStatusChange(in, out, wide); break; } /* SCardCancel */ case SC_CANCEL: { Result = (SERVER_DWORD) TS_SCardCancel(in, out); break; } /* SCardLocateCardsByATR */ case SC_LOCATE_CARDS_BY_ATR: /* SCardLocateCardsByATRA */ case SC_LOCATE_CARDS_BY_ATR + 4: /* SCardLocateCardsByATRW */ { RD_BOOL wide = request != SC_LOCATE_CARDS_BY_ATR; Result = (SERVER_DWORD) TS_SCardLocateCardsByATR(in, out, wide); break; } /* SCardBeginTransaction */ case SC_BEGIN_TRANSACTION: { Result = (SERVER_DWORD) TS_SCardBeginTransaction(in, out); break; } /* SCardBeginTransaction */ case SC_END_TRANSACTION: { Result = (SERVER_DWORD) TS_SCardEndTransaction(in, out); break; } /* ScardTransmit */ case SC_TRANSMIT: { Result = (SERVER_DWORD) TS_SCardTransmit(in, out); break; } /* SCardControl */ case SC_CONTROL: { Result = (SERVER_DWORD) TS_SCardControl(in, out); break; } /* SCardGetAttrib */ #ifndef WITH_PCSC120 case SC_GETATTRIB: { Result = (SERVER_DWORD) TS_SCardGetAttrib(in, out); break; } #endif case SC_ACCESS_STARTED_EVENT: { Result = (SERVER_DWORD) TS_SCardAccessStartedEvent(in, out); break; } case SC_STATUS: /* SCardStatusA */ case SC_STATUS + 4: /* SCardStatusW */ { RD_BOOL wide = request != SC_STATUS; Result = (SERVER_DWORD) TS_SCardStatus(in, out, wide); break; } case SC_STATE: /* SCardState */ { Result = (SERVER_DWORD) TS_SCardState(in, out); break; } default: { warning("SCARD: Unknown function %d\n", (int) request); Result = 0x80100014; out_uint8s(out, 256); break; } } #if 0 out_uint32_le(out, 0x00000000); #endif /* Setting modified variables */ pend = out->p; /* setting data size */ out->p = psize; out_uint32_le(out, pend - psize - 16); /* setting status code */ out->p = pStatusCode; out_uint32_le(out, Result); /* finish */ out->p = pend; addToEnd = (pend - pStatusCode) % 16; if (addToEnd < 16 && addToEnd > 0) { out_uint8s(out, addToEnd); } return RD_STATUS_SUCCESS; } /* Thread functions */ static STREAM duplicateStream(PMEM_HANDLE * handle, STREAM s, uint32 buffer_size, RD_BOOL isInputStream) { STREAM d = SC_xmalloc(handle, sizeof(struct stream)); if (d != NULL) { if (isInputStream) d->size = (size_t) (s->end) - (size_t) (s->data); else if (buffer_size < s->size) d->size = s->size; else d->size = buffer_size; d->data = SC_xmalloc(handle, d->size); d->end = (void *) ((size_t) (d->data) + (size_t) (s->end) - (size_t) (s->data)); d->p = (void *) ((size_t) (d->data) + (size_t) (s->p) - (size_t) (s->data)); d->iso_hdr = (void *) ((size_t) (d->data) + (size_t) (s->iso_hdr) - (size_t) (s->data)); d->mcs_hdr = (void *) ((size_t) (d->data) + (size_t) (s->mcs_hdr) - (size_t) (s->data)); d->sec_hdr = (void *) ((size_t) (d->data) + (size_t) (s->sec_hdr) - (size_t) (s->data)); d->sec_hdr = (void *) ((size_t) (d->data) + (size_t) (s->sec_hdr) - (size_t) (s->data)); d->rdp_hdr = (void *) ((size_t) (d->data) + (size_t) (s->rdp_hdr) - (size_t) (s->data)); d->channel_hdr = (void *) ((size_t) (d->data) + (size_t) (s->channel_hdr) - (size_t) (s->data)); if (isInputStream) memcpy(d->data, s->data, (size_t) (s->end) - (size_t) (s->data)); else memcpy(d->data, s->data, (size_t) (s->p) - (size_t) (s->data)); } return d; } /* Currently unused */ #if 0 static void freeStream(PMEM_HANDLE * handle, STREAM s) { if (s != NULL) { if (s->data != NULL) SC_xfree(handle, s->data); SC_xfree(handle, s); } } #endif static PSCThreadData SC_addToQueue(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) { PMEM_HANDLE lcHandle = NULL; PSCThreadData data = SC_xmalloc(&lcHandle, sizeof(TSCThreadData)); if (!data) return NULL; else { data->memHandle = lcHandle; data->device = curDevice; data->id = curId; data->epoch = curEpoch; data->handle = handle; data->request = request; data->in = duplicateStream(&(data->memHandle), in, 0, SC_TRUE); if (data->in == NULL) { SC_xfreeallmemory(&(data->memHandle)); return NULL; } data->out = duplicateStream(&(data->memHandle), out, OUT_STREAM_SIZE + curBytesOut, SC_FALSE); if (data->out == NULL) { SC_xfreeallmemory(&(data->memHandle)); return NULL; } data->next = NULL; pthread_mutex_lock(&queueAccess); if (queueLast) queueLast->next = data; queueLast = data; if (!queueFirst) queueFirst = data; pthread_cond_broadcast(&queueEmpty); pthread_mutex_unlock(&queueAccess); } return data; } static void SC_destroyThreadData(PSCThreadData data) { if (data) { PMEM_HANDLE handle = data->memHandle; SC_xfreeallmemory(&handle); } } static PSCThreadData SC_getNextInQueue() { PSCThreadData Result = NULL; pthread_mutex_lock(&queueAccess); while (queueFirst == NULL) pthread_cond_wait(&queueEmpty, &queueAccess); Result = queueFirst; queueFirst = queueFirst->next; if (!queueFirst) { queueLast = NULL; } Result->next = NULL; pthread_mutex_unlock(&queueAccess); return Result; } static void SC_deviceControl(PSCThreadData data) { size_t buffer_len = 0; scard_device_control(data->handle, data->request, data->in, data->out); buffer_len = (size_t) data->out->p - (size_t) data->out->data; /* if iorequest belongs to another epoch, don't send response back to server due to it's considered as abdonend. */ if (data->epoch == curEpoch) rdpdr_send_completion(data->device, data->id, 0, buffer_len, data->out->data, buffer_len); SC_destroyThreadData(data); } static void * thread_function(PThreadListElement listElement) { pthread_mutex_lock(&listElement->busy); while (1) { while (listElement->data == NULL) pthread_cond_wait(&listElement->nodata, &listElement->busy); SC_deviceControl(listElement->data); listElement->data = NULL; } pthread_mutex_unlock(&listElement->busy); pthread_exit(NULL); return NULL; } static void SC_handleRequest(PSCThreadData data) { int Result = 0; PThreadListElement cur; for (cur = threadList; cur != NULL; cur = cur->next) { if (cur->data == NULL) { pthread_mutex_lock(&cur->busy); /* double check with lock held.... */ if (cur->data != NULL) { pthread_mutex_unlock(&cur->busy); continue; } /* Wake up thread */ cur->data = data; pthread_cond_broadcast(&cur->nodata); pthread_mutex_unlock(&cur->busy); return; } } cur = SC_xmalloc(&threadListHandle, sizeof(TThreadListElement)); if (!cur) return; threadCount++; pthread_mutex_init(&cur->busy, NULL); pthread_cond_init(&cur->nodata, NULL); cur->data = data; Result = pthread_create(&cur->thread, NULL, (void *(*)(void *)) thread_function, cur); if (0 != Result) { error("[THREAD CREATE ERROR 0x%.8x]\n", Result); SC_xfree(&threadListHandle, cur); SC_destroyThreadData(data); data = NULL; } cur->next = threadList; threadList = cur; } static void * queue_handler_function(void *data) { PSCThreadData cur_data = NULL; while (1) { cur_data = SC_getNextInQueue(); switch (cur_data->request) { case SC_ESTABLISH_CONTEXT: case SC_RELEASE_CONTEXT: { SC_deviceControl(cur_data); break; } default: { SC_handleRequest(cur_data); break; } } } return NULL; } static RD_NTSTATUS thread_wrapper(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) { if (SC_addToQueue(handle, request, in, out)) return RD_STATUS_PENDING | 0xC0000000; else return RD_STATUS_NO_SUCH_FILE; } DEVICE_FNS scard_fns = { scard_create, scard_close, scard_read, scard_write, thread_wrapper }; #endif /* MAKE_PROTO */ void scard_lock(int lock) { if (!scard_mutex) { int i; scard_mutex = (pthread_mutex_t **) xmalloc(sizeof(pthread_mutex_t *) * SCARD_LOCK_LAST); for (i = 0; i < SCARD_LOCK_LAST; i++) { scard_mutex[i] = NULL; } } if (!scard_mutex[lock]) { scard_mutex[lock] = (pthread_mutex_t *) xmalloc(sizeof(pthread_mutex_t)); pthread_mutex_init(scard_mutex[lock], NULL); } pthread_mutex_lock(scard_mutex[lock]); } void scard_unlock(int lock) { pthread_mutex_unlock(scard_mutex[lock]); } void scard_reset_state() { curDevice = 0; curId = 0; curBytesOut = 0; queueFirst = queueLast = NULL; } rdesktop-1.8.3/seamless.c0000664000770100510440000002430012404241351014250 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Seamless Windows support Copyright 2005-2008 Peter Astrand for Cendio AB Copyright 2007-2008 Pierre Ossman for Cendio AB Copyright 2013-2014 Henrik Andersson for Cendio AB 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 3 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, see . */ #include "rdesktop.h" #include #include #ifdef WITH_DEBUG_SEAMLESS #define DEBUG_SEAMLESS(args) printf args; #else #define DEBUG_SEAMLESS(args) #endif extern RD_BOOL g_seamless_rdp; static VCHANNEL *seamless_channel; static unsigned int seamless_serial; static char *seamless_rest = NULL; static char icon_buf[1024]; static char * seamless_get_token(char **s) { char *comma, *head; head = *s; if (!head) return NULL; comma = strchr(head, ','); if (comma) { *comma = '\0'; *s = comma + 1; } else { *s = NULL; } return head; } static RD_BOOL seamless_process_line(const char *line, void *data) { char *p, *l; char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8; unsigned long id, flags; char *endptr; l = xstrdup(line); p = l; DEBUG_SEAMLESS(("seamlessrdp got:%s\n", p)); tok1 = seamless_get_token(&p); tok2 = seamless_get_token(&p); tok3 = seamless_get_token(&p); tok4 = seamless_get_token(&p); tok5 = seamless_get_token(&p); tok6 = seamless_get_token(&p); tok7 = seamless_get_token(&p); tok8 = seamless_get_token(&p); if (!strcmp("CREATE", tok1)) { unsigned long group, parent; if (!tok6) return False; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; group = strtoul(tok4, &endptr, 0); if (*endptr) return False; parent = strtoul(tok5, &endptr, 0); if (*endptr) return False; flags = strtoul(tok6, &endptr, 0); if (*endptr) return False; ui_seamless_create_window(id, group, parent, flags); } else if (!strcmp("DESTROY", tok1)) { if (!tok4) return False; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; flags = strtoul(tok4, &endptr, 0); if (*endptr) return False; ui_seamless_destroy_window(id, flags); } else if (!strcmp("DESTROYGRP", tok1)) { if (!tok4) return False; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; flags = strtoul(tok4, &endptr, 0); if (*endptr) return False; ui_seamless_destroy_group(id, flags); } else if (!strcmp("SETICON", tok1)) { int chunk, width, height, len; char byte[3]; if (!tok8) return False; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; chunk = strtoul(tok4, &endptr, 0); if (*endptr) return False; width = strtoul(tok6, &endptr, 0); if (*endptr) return False; height = strtoul(tok7, &endptr, 0); if (*endptr) return False; byte[2] = '\0'; len = 0; while (*tok8 != '\0') { byte[0] = *tok8; tok8++; if (*tok8 == '\0') return False; byte[1] = *tok8; tok8++; icon_buf[len] = strtol(byte, NULL, 16); len++; } ui_seamless_seticon(id, tok5, width, height, chunk, icon_buf, len); } else if (!strcmp("DELICON", tok1)) { int width, height; if (!tok6) return False; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; width = strtoul(tok5, &endptr, 0); if (*endptr) return False; height = strtoul(tok6, &endptr, 0); if (*endptr) return False; ui_seamless_delicon(id, tok4, width, height); } else if (!strcmp("POSITION", tok1)) { int x, y, width, height; if (!tok8) return False; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; x = strtol(tok4, &endptr, 0); if (*endptr) return False; y = strtol(tok5, &endptr, 0); if (*endptr) return False; width = strtol(tok6, &endptr, 0); if (*endptr) return False; height = strtol(tok7, &endptr, 0); if (*endptr) return False; flags = strtoul(tok8, &endptr, 0); if (*endptr) return False; ui_seamless_move_window(id, x, y, width, height, flags); } else if (!strcmp("ZCHANGE", tok1)) { unsigned long behind; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; behind = strtoul(tok4, &endptr, 0); if (*endptr) return False; flags = strtoul(tok5, &endptr, 0); if (*endptr) return False; ui_seamless_restack_window(id, behind, flags); } else if (!strcmp("TITLE", tok1)) { if (!tok5) return False; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; flags = strtoul(tok5, &endptr, 0); if (*endptr) return False; ui_seamless_settitle(id, tok4, flags); } else if (!strcmp("STATE", tok1)) { unsigned int state; if (!tok5) return False; id = strtoul(tok3, &endptr, 0); if (*endptr) return False; state = strtoul(tok4, &endptr, 0); if (*endptr) return False; flags = strtoul(tok5, &endptr, 0); if (*endptr) return False; ui_seamless_setstate(id, state, flags); } else if (!strcmp("DEBUG", tok1)) { DEBUG_SEAMLESS(("SeamlessRDP:%s\n", line)); } else if (!strcmp("SYNCBEGIN", tok1)) { if (!tok3) return False; flags = strtoul(tok3, &endptr, 0); if (*endptr) return False; ui_seamless_syncbegin(flags); } else if (!strcmp("SYNCEND", tok1)) { if (!tok3) return False; flags = strtoul(tok3, &endptr, 0); if (*endptr) return False; /* do nothing, currently */ } else if (!strcmp("HELLO", tok1)) { if (!tok3) return False; flags = strtoul(tok3, &endptr, 0); if (*endptr) return False; ui_seamless_begin(! !(flags & SEAMLESSRDP_HELLO_HIDDEN)); } else if (!strcmp("ACK", tok1)) { unsigned int serial; serial = strtoul(tok3, &endptr, 0); if (*endptr) return False; ui_seamless_ack(serial); } else if (!strcmp("HIDE", tok1)) { if (!tok3) return False; flags = strtoul(tok3, &endptr, 0); if (*endptr) return False; ui_seamless_hide_desktop(); } else if (!strcmp("UNHIDE", tok1)) { if (!tok3) return False; flags = strtoul(tok3, &endptr, 0); if (*endptr) return False; ui_seamless_unhide_desktop(); } xfree(l); return True; } static RD_BOOL seamless_line_handler(const char *line, void *data) { if (!seamless_process_line(line, data)) { warning("SeamlessRDP: Invalid request:%s\n", line); } return True; } static void seamless_process(STREAM s) { unsigned int pkglen; char *buf; pkglen = s->end - s->p; /* str_handle_lines requires null terminated strings */ buf = xmalloc(pkglen + 1); STRNCPY(buf, (char *) s->p, pkglen + 1); #if 0 printf("seamless recv:\n"); hexdump(s->p, pkglen); #endif str_handle_lines(buf, &seamless_rest, seamless_line_handler, NULL); xfree(buf); } RD_BOOL seamless_init(void) { if (!g_seamless_rdp) return False; seamless_serial = 0; seamless_channel = channel_register("seamrdp", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, seamless_process); return (seamless_channel != NULL); } void seamless_reset_state(void) { if (seamless_rest != NULL) { xfree(seamless_rest); seamless_rest = NULL; } } static unsigned int seamless_send(const char *command, const char *format, ...) { STREAM s; size_t len; va_list argp; char *escaped, buf[1025]; len = snprintf(buf, sizeof(buf) - 1, "%s,%u,", command, seamless_serial); assert(len < (sizeof(buf) - 1)); va_start(argp, format); len += vsnprintf(buf + len, sizeof(buf) - len - 1, format, argp); va_end(argp); assert(len < (sizeof(buf) - 1)); escaped = utils_string_escape(buf); len = snprintf(buf, sizeof(buf), "%s", escaped); free(escaped); assert(len < (sizeof(buf) - 1)); buf[len] = '\n'; buf[len + 1] = '\0'; len++; s = channel_init(seamless_channel, len); out_uint8p(s, buf, len) s_mark_end(s); DEBUG_SEAMLESS(("seamlessrdp sending:%s", buf)); #if 0 printf("seamless send:\n"); hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); #endif channel_send(s, seamless_channel); return seamless_serial++; } unsigned int seamless_send_sync() { if (!g_seamless_rdp) return (unsigned int) -1; return seamless_send("SYNC", ""); } unsigned int seamless_send_state(unsigned long id, unsigned int state, unsigned long flags) { if (!g_seamless_rdp) return (unsigned int) -1; return seamless_send("STATE", "0x%08lx,0x%x,0x%lx", id, state, flags); } unsigned int seamless_send_position(unsigned long id, int x, int y, int width, int height, unsigned long flags) { return seamless_send("POSITION", "0x%08lx,%d,%d,%d,%d,0x%lx", id, x, y, width, height, flags); } /* Update select timeout */ void seamless_select_timeout(struct timeval *tv) { struct timeval ourtimeout = { 0, SEAMLESSRDP_POSITION_TIMER }; if (g_seamless_rdp) { if (timercmp(&ourtimeout, tv, <)) { tv->tv_sec = ourtimeout.tv_sec; tv->tv_usec = ourtimeout.tv_usec; } } } unsigned int seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags) { if (!g_seamless_rdp) return (unsigned int) -1; return seamless_send("ZCHANGE", "0x%08lx,0x%08lx,0x%lx", id, below, flags); } unsigned int seamless_send_focus(unsigned long id, unsigned long flags) { if (!g_seamless_rdp) return (unsigned int) -1; return seamless_send("FOCUS", "0x%08lx,0x%lx", id, flags); } /* Send client-to-server message to destroy process on the server. */ unsigned int seamless_send_destroy(unsigned long id) { return seamless_send("DESTROY", "0x%08lx", id); } unsigned int seamless_send_spawn(char *cmdline) { unsigned int res; if (!g_seamless_rdp) return (unsigned int) -1; res = seamless_send("SPAWN", cmdline); return res; } unsigned int seamless_send_persistent(RD_BOOL enable) { unsigned int res; if (!g_seamless_rdp) return (unsigned int) -1; printf("%s persistent seamless mode.\n", enable?"Enable":"Disable"); res = seamless_send("PERSISTENT", "%d", enable); return res; } rdesktop-1.8.3/secure.c0000664000770100510440000005704212275116407013744 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - RDP encryption and licensing Copyright (C) Matthew Chapman 1999-2008 Copyright 2005-2011 Peter Astrand for Cendio AB 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 3 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, see . */ #include "rdesktop.h" #include "ssl.h" extern char g_hostname[16]; extern int g_width; extern int g_height; extern unsigned int g_keylayout; extern int g_keyboard_type; extern int g_keyboard_subtype; extern int g_keyboard_functionkeys; extern RD_BOOL g_encryption; extern RD_BOOL g_licence_issued; extern RD_BOOL g_licence_error_result; extern RDP_VERSION g_rdp_version; extern RD_BOOL g_console_session; extern uint32 g_redirect_session_id; extern int g_server_depth; extern VCHANNEL g_channels[]; extern unsigned int g_num_channels; extern uint8 g_client_random[SEC_RANDOM_SIZE]; static int g_rc4_key_len; static RDSSL_RC4 g_rc4_decrypt_key; static RDSSL_RC4 g_rc4_encrypt_key; static uint32 g_server_public_key_len; static uint8 g_sec_sign_key[16]; static uint8 g_sec_decrypt_key[16]; static uint8 g_sec_encrypt_key[16]; static uint8 g_sec_decrypt_update_key[16]; static uint8 g_sec_encrypt_update_key[16]; static uint8 g_sec_crypted_random[SEC_MAX_MODULUS_SIZE]; uint16 g_server_rdp_version = 0; /* These values must be available to reset state - Session Directory */ static int g_sec_encrypt_use_count = 0; static int g_sec_decrypt_use_count = 0; /* * I believe this is based on SSLv3 with the following differences: * MAC algorithm (5.2.3.1) uses only 32-bit length in place of seq_num/type/length fields * MAC algorithm uses SHA1 and MD5 for the two hash functions instead of one or other * key_block algorithm (6.2.2) uses 'X', 'YY', 'ZZZ' instead of 'A', 'BB', 'CCC' * key_block partitioning is different (16 bytes each: MAC secret, decrypt key, encrypt key) * encryption/decryption keys updated every 4096 packets * See http://wp.netscape.com/eng/ssl3/draft302.txt */ /* * 48-byte transformation used to generate master secret (6.1) and key material (6.2.2). * Both SHA1 and MD5 algorithms are used. */ void sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt) { uint8 shasig[20]; uint8 pad[4]; RDSSL_SHA1 sha1; RDSSL_MD5 md5; int i; for (i = 0; i < 3; i++) { memset(pad, salt + i, i + 1); rdssl_sha1_init(&sha1); rdssl_sha1_update(&sha1, pad, i + 1); rdssl_sha1_update(&sha1, in, 48); rdssl_sha1_update(&sha1, salt1, 32); rdssl_sha1_update(&sha1, salt2, 32); rdssl_sha1_final(&sha1, shasig); rdssl_md5_init(&md5); rdssl_md5_update(&md5, in, 48); rdssl_md5_update(&md5, shasig, 20); rdssl_md5_final(&md5, &out[i * 16]); } } /* * 16-byte transformation used to generate export keys (6.2.2). */ void sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2) { RDSSL_MD5 md5; rdssl_md5_init(&md5); rdssl_md5_update(&md5, in, 16); rdssl_md5_update(&md5, salt1, 32); rdssl_md5_update(&md5, salt2, 32); rdssl_md5_final(&md5, out); } /* * 16-byte sha1 hash */ void sec_hash_sha1_16(uint8 * out, uint8 * in, uint8 * salt1) { RDSSL_SHA1 sha1; rdssl_sha1_init(&sha1); rdssl_sha1_update(&sha1, in, 16); rdssl_sha1_update(&sha1, salt1, 16); rdssl_sha1_final(&sha1, out); } /* create string from hash */ void sec_hash_to_string(char *out, int out_size, uint8 * in, int in_size) { int k; memset(out, 0, out_size); for (k = 0; k < in_size; k++, out += 2) { sprintf(out, "%.2x", in[k]); } } /* Reduce key entropy from 64 to 40 bits */ static void sec_make_40bit(uint8 * key) { key[0] = 0xd1; key[1] = 0x26; key[2] = 0x9e; } /* Generate encryption keys given client and server randoms */ static void sec_generate_keys(uint8 * client_random, uint8 * server_random, int rc4_key_size) { uint8 pre_master_secret[48]; uint8 master_secret[48]; uint8 key_block[48]; /* Construct pre-master secret */ memcpy(pre_master_secret, client_random, 24); memcpy(pre_master_secret + 24, server_random, 24); /* Generate master secret and then key material */ sec_hash_48(master_secret, pre_master_secret, client_random, server_random, 'A'); sec_hash_48(key_block, master_secret, client_random, server_random, 'X'); /* First 16 bytes of key material is MAC secret */ memcpy(g_sec_sign_key, key_block, 16); /* Generate export keys from next two blocks of 16 bytes */ sec_hash_16(g_sec_decrypt_key, &key_block[16], client_random, server_random); sec_hash_16(g_sec_encrypt_key, &key_block[32], client_random, server_random); if (rc4_key_size == 1) { DEBUG(("40-bit encryption enabled\n")); sec_make_40bit(g_sec_sign_key); sec_make_40bit(g_sec_decrypt_key); sec_make_40bit(g_sec_encrypt_key); g_rc4_key_len = 8; } else { DEBUG(("rc_4_key_size == %d, 128-bit encryption enabled\n", rc4_key_size)); g_rc4_key_len = 16; } /* Save initial RC4 keys as update keys */ memcpy(g_sec_decrypt_update_key, g_sec_decrypt_key, 16); memcpy(g_sec_encrypt_update_key, g_sec_encrypt_key, 16); /* Initialise RC4 state arrays */ rdssl_rc4_set_key(&g_rc4_decrypt_key, g_sec_decrypt_key, g_rc4_key_len); rdssl_rc4_set_key(&g_rc4_encrypt_key, g_sec_encrypt_key, g_rc4_key_len); } static uint8 pad_54[40] = { 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54 }; static uint8 pad_92[48] = { 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92 }; /* Output a uint32 into a buffer (little-endian) */ void buf_out_uint32(uint8 * buffer, uint32 value) { buffer[0] = (value) & 0xff; buffer[1] = (value >> 8) & 0xff; buffer[2] = (value >> 16) & 0xff; buffer[3] = (value >> 24) & 0xff; } /* Generate a MAC hash (5.2.3.1), using a combination of SHA1 and MD5 */ void sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, int datalen) { uint8 shasig[20]; uint8 md5sig[16]; uint8 lenhdr[4]; RDSSL_SHA1 sha1; RDSSL_MD5 md5; buf_out_uint32(lenhdr, datalen); rdssl_sha1_init(&sha1); rdssl_sha1_update(&sha1, session_key, keylen); rdssl_sha1_update(&sha1, pad_54, 40); rdssl_sha1_update(&sha1, lenhdr, 4); rdssl_sha1_update(&sha1, data, datalen); rdssl_sha1_final(&sha1, shasig); rdssl_md5_init(&md5); rdssl_md5_update(&md5, session_key, keylen); rdssl_md5_update(&md5, pad_92, 48); rdssl_md5_update(&md5, shasig, 20); rdssl_md5_final(&md5, md5sig); memcpy(signature, md5sig, siglen); } /* Update an encryption key */ static void sec_update(uint8 * key, uint8 * update_key) { uint8 shasig[20]; RDSSL_SHA1 sha1; RDSSL_MD5 md5; RDSSL_RC4 update; rdssl_sha1_init(&sha1); rdssl_sha1_update(&sha1, update_key, g_rc4_key_len); rdssl_sha1_update(&sha1, pad_54, 40); rdssl_sha1_update(&sha1, key, g_rc4_key_len); rdssl_sha1_final(&sha1, shasig); rdssl_md5_init(&md5); rdssl_md5_update(&md5, update_key, g_rc4_key_len); rdssl_md5_update(&md5, pad_92, 48); rdssl_md5_update(&md5, shasig, 20); rdssl_md5_final(&md5, key); rdssl_rc4_set_key(&update, key, g_rc4_key_len); rdssl_rc4_crypt(&update, key, key, g_rc4_key_len); if (g_rc4_key_len == 8) sec_make_40bit(key); } /* Encrypt data using RC4 */ static void sec_encrypt(uint8 * data, int length) { if (g_sec_encrypt_use_count == 4096) { sec_update(g_sec_encrypt_key, g_sec_encrypt_update_key); rdssl_rc4_set_key(&g_rc4_encrypt_key, g_sec_encrypt_key, g_rc4_key_len); g_sec_encrypt_use_count = 0; } rdssl_rc4_crypt(&g_rc4_encrypt_key, data, data, length); g_sec_encrypt_use_count++; } /* Decrypt data using RC4 */ void sec_decrypt(uint8 * data, int length) { if (g_sec_decrypt_use_count == 4096) { sec_update(g_sec_decrypt_key, g_sec_decrypt_update_key); rdssl_rc4_set_key(&g_rc4_decrypt_key, g_sec_decrypt_key, g_rc4_key_len); g_sec_decrypt_use_count = 0; } rdssl_rc4_crypt(&g_rc4_decrypt_key, data, data, length); g_sec_decrypt_use_count++; } /* Perform an RSA public key encryption operation */ static void sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, uint8 * exponent) { rdssl_rsa_encrypt(out, in, len, modulus_size, modulus, exponent); } /* Initialise secure transport packet */ STREAM sec_init(uint32 flags, int maxlen) { int hdrlen; STREAM s; if (!g_licence_issued && !g_licence_error_result) hdrlen = (flags & SEC_ENCRYPT) ? 12 : 4; else hdrlen = (flags & SEC_ENCRYPT) ? 12 : 0; s = mcs_init(maxlen + hdrlen); s_push_layer(s, sec_hdr, hdrlen); return s; } /* Transmit secure transport packet over specified channel */ void sec_send_to_channel(STREAM s, uint32 flags, uint16 channel) { int datalen; #ifdef WITH_SCARD scard_lock(SCARD_LOCK_SEC); #endif s_pop_layer(s, sec_hdr); if ((!g_licence_issued && !g_licence_error_result) || (flags & SEC_ENCRYPT)) out_uint32_le(s, flags); if (flags & SEC_ENCRYPT) { flags &= ~SEC_ENCRYPT; datalen = s->end - s->p - 8; #if WITH_DEBUG DEBUG(("Sending encrypted packet:\n")); hexdump(s->p + 8, datalen); #endif sec_sign(s->p, 8, g_sec_sign_key, g_rc4_key_len, s->p + 8, datalen); sec_encrypt(s->p + 8, datalen); } mcs_send_to_channel(s, channel); #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_SEC); #endif } /* Transmit secure transport packet */ void sec_send(STREAM s, uint32 flags) { sec_send_to_channel(s, flags, MCS_GLOBAL_CHANNEL); } /* Transfer the client random to the server */ static void sec_establish_key(void) { uint32 length = g_server_public_key_len + SEC_PADDING_SIZE; uint32 flags = SEC_CLIENT_RANDOM; STREAM s; s = sec_init(flags, length + 4); out_uint32_le(s, length); out_uint8p(s, g_sec_crypted_random, g_server_public_key_len); out_uint8s(s, SEC_PADDING_SIZE); s_mark_end(s); sec_send(s, flags); } /* Output connect initial data blob */ static void sec_out_mcs_data(STREAM s, uint32 selected_protocol) { int hostlen = 2 * strlen(g_hostname); int length = 162 + 76 + 12 + 4; unsigned int i; if (g_num_channels > 0) length += g_num_channels * 12 + 8; if (hostlen > 30) hostlen = 30; /* Generic Conference Control (T.124) ConferenceCreateRequest */ out_uint16_be(s, 5); out_uint16_be(s, 0x14); out_uint8(s, 0x7c); out_uint16_be(s, 1); out_uint16_be(s, (length | 0x8000)); /* remaining length */ out_uint16_be(s, 8); /* length? */ out_uint16_be(s, 16); out_uint8(s, 0); out_uint16_le(s, 0xc001); out_uint8(s, 0); out_uint32_le(s, 0x61637544); /* OEM ID: "Duca", as in Ducati. */ out_uint16_be(s, ((length - 14) | 0x8000)); /* remaining length */ /* Client information */ out_uint16_le(s, SEC_TAG_CLI_INFO); out_uint16_le(s, 216); /* length */ out_uint16_le(s, (g_rdp_version >= RDP_V5) ? 4 : 1); /* RDP version. 1 == RDP4, 4 >= RDP5 to RDP8 */ out_uint16_le(s, 8); out_uint16_le(s, g_width); out_uint16_le(s, g_height); out_uint16_le(s, 0xca01); out_uint16_le(s, 0xaa03); out_uint32_le(s, g_keylayout); out_uint32_le(s, 2600); /* Client build. We are now 2600 compatible :-) */ /* Unicode name of client, padded to 32 bytes */ rdp_out_unistr(s, g_hostname, hostlen); out_uint8s(s, 30 - hostlen); /* See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceddk40/html/cxtsksupportingremotedesktopprotocol.asp */ out_uint32_le(s, g_keyboard_type); out_uint32_le(s, g_keyboard_subtype); out_uint32_le(s, g_keyboard_functionkeys); out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */ out_uint16_le(s, 0xca01); /* colour depth? */ out_uint16_le(s, 1); out_uint32(s, 0); out_uint8(s, g_server_depth); out_uint16_le(s, 0x0700); out_uint8(s, 0); out_uint32_le(s, 1); out_uint8s(s, 64); out_uint32_le(s, selected_protocol); /* End of client info */ /* Write a Client Cluster Data (TS_UD_CS_CLUSTER) */ uint32 cluster_flags = 0; out_uint16_le(s, SEC_TAG_CLI_CLUSTER); /* header.type */ out_uint16_le(s, 12); /* length */ cluster_flags |= SEC_CC_REDIRECTION_SUPPORTED; cluster_flags |= (SEC_CC_REDIRECT_VERSION_3 << 2); if (g_console_session || g_redirect_session_id != 0) cluster_flags |= SEC_CC_REDIRECT_SESSIONID_FIELD_VALID; out_uint32_le(s, cluster_flags); out_uint32(s, g_redirect_session_id); /* Client encryption settings */ out_uint16_le(s, SEC_TAG_CLI_CRYPT); out_uint16_le(s, 12); /* length */ out_uint32_le(s, g_encryption ? 0x3 : 0); /* encryption supported, 128-bit supported */ out_uint32(s, 0); /* Unknown */ DEBUG_RDP5(("g_num_channels is %d\n", g_num_channels)); if (g_num_channels > 0) { out_uint16_le(s, SEC_TAG_CLI_CHANNELS); out_uint16_le(s, g_num_channels * 12 + 8); /* length */ out_uint32_le(s, g_num_channels); /* number of virtual channels */ for (i = 0; i < g_num_channels; i++) { DEBUG_RDP5(("Requesting channel %s\n", g_channels[i].name)); out_uint8a(s, g_channels[i].name, 8); out_uint32_be(s, g_channels[i].flags); } } s_mark_end(s); } /* Parse a public key structure */ static RD_BOOL sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent) { uint32 magic, modulus_len; in_uint32_le(s, magic); if (magic != SEC_RSA_MAGIC) { error("RSA magic 0x%x\n", magic); return False; } in_uint32_le(s, modulus_len); modulus_len -= SEC_PADDING_SIZE; if ((modulus_len < SEC_MODULUS_SIZE) || (modulus_len > SEC_MAX_MODULUS_SIZE)) { error("Bad server public key size (%u bits)\n", modulus_len * 8); return False; } in_uint8s(s, 8); /* modulus_bits, unknown */ in_uint8a(s, exponent, SEC_EXPONENT_SIZE); in_uint8a(s, modulus, modulus_len); in_uint8s(s, SEC_PADDING_SIZE); g_server_public_key_len = modulus_len; return s_check(s); } /* Parse a public signature structure */ static RD_BOOL sec_parse_public_sig(STREAM s, uint32 len, uint8 * modulus, uint8 * exponent) { uint8 signature[SEC_MAX_MODULUS_SIZE]; uint32 sig_len; if (len != 72) { return True; } memset(signature, 0, sizeof(signature)); sig_len = len - 8; in_uint8a(s, signature, sig_len); return rdssl_sig_ok(exponent, SEC_EXPONENT_SIZE, modulus, g_server_public_key_len, signature, sig_len); } /* Parse a crypto information structure */ static RD_BOOL sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, uint8 ** server_random, uint8 * modulus, uint8 * exponent) { uint32 crypt_level, random_len, rsa_info_len; uint32 cacert_len, cert_len, flags; RDSSL_CERT *cacert, *server_cert; RDSSL_RKEY *server_public_key; uint16 tag, length; uint8 *next_tag, *end; in_uint32_le(s, *rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */ in_uint32_le(s, crypt_level); /* 1 = low, 2 = medium, 3 = high */ if (crypt_level == 0) { /* no encryption */ return False; } in_uint32_le(s, random_len); in_uint32_le(s, rsa_info_len); if (random_len != SEC_RANDOM_SIZE) { error("random len %d, expected %d\n", random_len, SEC_RANDOM_SIZE); return False; } in_uint8p(s, *server_random, random_len); /* RSA info */ end = s->p + rsa_info_len; if (end > s->end) return False; in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */ if (flags & 1) { DEBUG_RDP5(("We're going for the RDP4-style encryption\n")); in_uint8s(s, 8); /* unknown */ while (s->p < end) { in_uint16_le(s, tag); in_uint16_le(s, length); next_tag = s->p + length; switch (tag) { case SEC_TAG_PUBKEY: if (!sec_parse_public_key(s, modulus, exponent)) return False; DEBUG_RDP5(("Got Public key, RDP4-style\n")); break; case SEC_TAG_KEYSIG: if (!sec_parse_public_sig(s, length, modulus, exponent)) return False; break; default: unimpl("crypt tag 0x%x\n", tag); } s->p = next_tag; } } else { uint32 certcount; DEBUG_RDP5(("We're going for the RDP5-style encryption\n")); in_uint32_le(s, certcount); /* Number of certificates */ if (certcount < 2) { error("Server didn't send enough X509 certificates\n"); return False; } for (; certcount > 2; certcount--) { /* ignore all the certificates between the root and the signing CA */ uint32 ignorelen; RDSSL_CERT *ignorecert; DEBUG_RDP5(("Ignored certs left: %d\n", certcount)); in_uint32_le(s, ignorelen); DEBUG_RDP5(("Ignored Certificate length is %d\n", ignorelen)); ignorecert = rdssl_cert_read(s->p, ignorelen); in_uint8s(s, ignorelen); if (ignorecert == NULL) { /* XXX: error out? */ DEBUG_RDP5(("got a bad cert: this will probably screw up the rest of the communication\n")); } #ifdef WITH_DEBUG_RDP5 DEBUG_RDP5(("cert #%d (ignored):\n", certcount)); rdssl_cert_print_fp(stdout, ignorecert); #endif } /* Do da funky X.509 stuffy "How did I find out about this? I looked up and saw a bright light and when I came to I had a scar on my forehead and knew about X.500" - Peter Gutman in a early version of http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt */ in_uint32_le(s, cacert_len); DEBUG_RDP5(("CA Certificate length is %d\n", cacert_len)); cacert = rdssl_cert_read(s->p, cacert_len); in_uint8s(s, cacert_len); if (NULL == cacert) { error("Couldn't load CA Certificate from server\n"); return False; } in_uint32_le(s, cert_len); DEBUG_RDP5(("Certificate length is %d\n", cert_len)); server_cert = rdssl_cert_read(s->p, cert_len); in_uint8s(s, cert_len); if (NULL == server_cert) { rdssl_cert_free(cacert); error("Couldn't load Certificate from server\n"); return False; } if (!rdssl_certs_ok(server_cert, cacert)) { rdssl_cert_free(server_cert); rdssl_cert_free(cacert); error("Security error CA Certificate invalid\n"); return False; } rdssl_cert_free(cacert); in_uint8s(s, 16); /* Padding */ server_public_key = rdssl_cert_to_rkey(server_cert, &g_server_public_key_len); if (NULL == server_public_key) { DEBUG_RDP5(("Didn't parse X509 correctly\n")); rdssl_cert_free(server_cert); return False; } rdssl_cert_free(server_cert); if ((g_server_public_key_len < SEC_MODULUS_SIZE) || (g_server_public_key_len > SEC_MAX_MODULUS_SIZE)) { error("Bad server public key size (%u bits)\n", g_server_public_key_len * 8); rdssl_rkey_free(server_public_key); return False; } if (rdssl_rkey_get_exp_mod(server_public_key, exponent, SEC_EXPONENT_SIZE, modulus, SEC_MAX_MODULUS_SIZE) != 0) { error("Problem extracting RSA exponent, modulus"); rdssl_rkey_free(server_public_key); return False; } rdssl_rkey_free(server_public_key); return True; /* There's some garbage here we don't care about */ } return s_check_end(s); } /* Process crypto information blob */ static void sec_process_crypt_info(STREAM s) { uint8 *server_random = NULL; uint8 modulus[SEC_MAX_MODULUS_SIZE]; uint8 exponent[SEC_EXPONENT_SIZE]; uint32 rc4_key_size; memset(modulus, 0, sizeof(modulus)); memset(exponent, 0, sizeof(exponent)); if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, modulus, exponent)) { DEBUG(("Failed to parse crypt info\n")); return; } DEBUG(("Generating client random\n")); generate_random(g_client_random); sec_rsa_encrypt(g_sec_crypted_random, g_client_random, SEC_RANDOM_SIZE, g_server_public_key_len, modulus, exponent); sec_generate_keys(g_client_random, server_random, rc4_key_size); } /* Process SRV_INFO, find RDP version supported by server */ static void sec_process_srv_info(STREAM s) { in_uint16_le(s, g_server_rdp_version); DEBUG_RDP5(("Server RDP version is %d\n", g_server_rdp_version)); if (1 == g_server_rdp_version) { g_rdp_version = RDP_V4; g_server_depth = 8; } } /* Process connect response data blob */ void sec_process_mcs_data(STREAM s) { uint16 tag, length; uint8 *next_tag; uint8 len; in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */ in_uint8(s, len); if (len & 0x80) in_uint8(s, len); while (s->p < s->end) { in_uint16_le(s, tag); in_uint16_le(s, length); if (length <= 4) return; next_tag = s->p + length - 4; switch (tag) { case SEC_TAG_SRV_INFO: sec_process_srv_info(s); break; case SEC_TAG_SRV_CRYPT: sec_process_crypt_info(s); break; case SEC_TAG_SRV_CHANNELS: /* FIXME: We should parse this information and use it to map RDP5 channels to MCS channels */ break; default: unimpl("response tag 0x%x\n", tag); } s->p = next_tag; } } /* Receive secure transport packet */ STREAM sec_recv(uint8 * rdpver) { uint32 sec_flags; uint16 channel; STREAM s; while ((s = mcs_recv(&channel, rdpver)) != NULL) { if (rdpver != NULL) { if (*rdpver != 3) { if (*rdpver & 0x80) { in_uint8s(s, 8); /* signature */ sec_decrypt(s->p, s->end - s->p); } return s; } } if (g_encryption || (!g_licence_issued && !g_licence_error_result)) { in_uint32_le(s, sec_flags); if (g_encryption) { if (sec_flags & SEC_ENCRYPT) { in_uint8s(s, 8); /* signature */ sec_decrypt(s->p, s->end - s->p); } if (sec_flags & SEC_LICENCE_NEG) { licence_process(s); continue; } if (sec_flags & 0x0400) /* SEC_REDIRECT_ENCRYPT */ { uint8 swapbyte; in_uint8s(s, 8); /* signature */ sec_decrypt(s->p, s->end - s->p); /* Check for a redirect packet, starts with 00 04 */ if (s->p[0] == 0 && s->p[1] == 4) { /* for some reason the PDU and the length seem to be swapped. This isn't good, but we're going to do a byte for byte swap. So the first foure value appear as: 00 04 XX YY, where XX YY is the little endian length. We're going to use 04 00 as the PDU type, so after our swap this will look like: XX YY 04 00 */ swapbyte = s->p[0]; s->p[0] = s->p[2]; s->p[2] = swapbyte; swapbyte = s->p[1]; s->p[1] = s->p[3]; s->p[3] = swapbyte; swapbyte = s->p[2]; s->p[2] = s->p[3]; s->p[3] = swapbyte; } #ifdef WITH_DEBUG /* warning! this debug statement will show passwords in the clear! */ hexdump(s->p, s->end - s->p); #endif } } else { if ((sec_flags & 0xffff) == SEC_LICENCE_NEG) { licence_process(s); continue; } s->p -= 4; } } if (channel != MCS_GLOBAL_CHANNEL) { channel_process(s, channel); if (rdpver != NULL) *rdpver = 0xff; return s; } return s; } return NULL; } /* Establish a secure connection */ RD_BOOL sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect) { uint32 selected_proto; struct stream mcs_data; /* Start a MCS connect sequence */ if (!mcs_connect_start(server, username, domain, password, reconnect, &selected_proto)) return False; /* We exchange some RDP data during the MCS-Connect */ mcs_data.size = 512; mcs_data.p = mcs_data.data = (uint8 *) xmalloc(mcs_data.size); sec_out_mcs_data(&mcs_data, selected_proto); /* finialize the MCS connect sequence */ if (!mcs_connect_finalize(&mcs_data)) return False; /* sec_process_mcs_data(&mcs_data); */ if (g_encryption) sec_establish_key(); xfree(mcs_data.data); return True; } /* Disconnect a connection */ void sec_disconnect(void) { mcs_disconnect(); } /* reset the state of the sec layer */ void sec_reset_state(void) { g_server_rdp_version = 0; g_sec_encrypt_use_count = 0; g_sec_decrypt_use_count = 0; g_licence_issued = 0; g_licence_error_result = 0; mcs_reset_state(); } rdesktop-1.8.3/serial.c0000664000770100510440000006522611636625157013747 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ #include #include #include #include #include #ifdef HAVE_SYS_MODEM_H #include #endif #ifdef HAVE_SYS_FILIO_H #include #endif #ifdef HAVE_SYS_STRTIO_H #include #endif #include "rdesktop.h" #ifdef WITH_DEBUG_SERIAL #define DEBUG_SERIAL(args) printf args; #else #define DEBUG_SERIAL(args) #endif #define FILE_DEVICE_SERIAL_PORT 0x1b #define SERIAL_SET_BAUD_RATE 1 #define SERIAL_SET_QUEUE_SIZE 2 #define SERIAL_SET_LINE_CONTROL 3 #define SERIAL_SET_BREAK_ON 4 #define SERIAL_SET_BREAK_OFF 5 #define SERIAL_IMMEDIATE_CHAR 6 #define SERIAL_SET_TIMEOUTS 7 #define SERIAL_GET_TIMEOUTS 8 #define SERIAL_SET_DTR 9 #define SERIAL_CLR_DTR 10 #define SERIAL_RESET_DEVICE 11 #define SERIAL_SET_RTS 12 #define SERIAL_CLR_RTS 13 #define SERIAL_SET_XOFF 14 #define SERIAL_SET_XON 15 #define SERIAL_GET_WAIT_MASK 16 #define SERIAL_SET_WAIT_MASK 17 #define SERIAL_WAIT_ON_MASK 18 #define SERIAL_PURGE 19 #define SERIAL_GET_BAUD_RATE 20 #define SERIAL_GET_LINE_CONTROL 21 #define SERIAL_GET_CHARS 22 #define SERIAL_SET_CHARS 23 #define SERIAL_GET_HANDFLOW 24 #define SERIAL_SET_HANDFLOW 25 #define SERIAL_GET_MODEMSTATUS 26 #define SERIAL_GET_COMMSTATUS 27 #define SERIAL_XOFF_COUNTER 28 #define SERIAL_GET_PROPERTIES 29 #define SERIAL_GET_DTRRTS 30 #define SERIAL_LSRMST_INSERT 31 #define SERIAL_CONFIG_SIZE 32 #define SERIAL_GET_COMMCONFIG 33 #define SERIAL_SET_COMMCONFIG 34 #define SERIAL_GET_STATS 35 #define SERIAL_CLEAR_STATS 36 #define SERIAL_GET_MODEM_CONTROL 37 #define SERIAL_SET_MODEM_CONTROL 38 #define SERIAL_SET_FIFO_CONTROL 39 #define STOP_BITS_1 0 #define STOP_BITS_2 2 #define NO_PARITY 0 #define ODD_PARITY 1 #define EVEN_PARITY 2 #define SERIAL_PURGE_TXABORT 0x00000001 #define SERIAL_PURGE_RXABORT 0x00000002 #define SERIAL_PURGE_TXCLEAR 0x00000004 #define SERIAL_PURGE_RXCLEAR 0x00000008 /* SERIAL_WAIT_ON_MASK */ #define SERIAL_EV_RXCHAR 0x0001 /* Any Character received */ #define SERIAL_EV_RXFLAG 0x0002 /* Received certain character */ #define SERIAL_EV_TXEMPTY 0x0004 /* Transmitt Queue Empty */ #define SERIAL_EV_CTS 0x0008 /* CTS changed state */ #define SERIAL_EV_DSR 0x0010 /* DSR changed state */ #define SERIAL_EV_RLSD 0x0020 /* RLSD changed state */ #define SERIAL_EV_BREAK 0x0040 /* BREAK received */ #define SERIAL_EV_ERR 0x0080 /* Line status error occurred */ #define SERIAL_EV_RING 0x0100 /* Ring signal detected */ #define SERIAL_EV_PERR 0x0200 /* Printer error occured */ #define SERIAL_EV_RX80FULL 0x0400 /* Receive buffer is 80 percent full */ #define SERIAL_EV_EVENT1 0x0800 /* Provider specific event 1 */ #define SERIAL_EV_EVENT2 0x1000 /* Provider specific event 2 */ /* Modem Status */ #define SERIAL_MS_DTR 0x01 #define SERIAL_MS_RTS 0x02 #define SERIAL_MS_CTS 0x10 #define SERIAL_MS_DSR 0x20 #define SERIAL_MS_RNG 0x40 #define SERIAL_MS_CAR 0x80 /* Handflow */ #define SERIAL_DTR_CONTROL 0x01 #define SERIAL_CTS_HANDSHAKE 0x08 #define SERIAL_ERROR_ABORT 0x80000000 #define SERIAL_XON_HANDSHAKE 0x01 #define SERIAL_XOFF_HANDSHAKE 0x02 #define SERIAL_DSR_SENSITIVITY 0x40 #define SERIAL_CHAR_EOF 0 #define SERIAL_CHAR_ERROR 1 #define SERIAL_CHAR_BREAK 2 #define SERIAL_CHAR_EVENT 3 #define SERIAL_CHAR_XON 4 #define SERIAL_CHAR_XOFF 5 #ifndef CRTSCTS #define CRTSCTS 0 #endif /* FIONREAD should really do the same thing as TIOCINQ, where it is * not available */ #if !defined(TIOCINQ) && defined(FIONREAD) #define TIOCINQ FIONREAD #endif #if !defined(TIOCOUTQ) && defined(FIONWRITE) #define TIOCOUTQ FIONWRITE #endif extern RDPDR_DEVICE g_rdpdr_device[]; static SERIAL_DEVICE * get_serial_info(RD_NTHANDLE handle) { int index; for (index = 0; index < RDPDR_MAX_DEVICES; index++) { if (handle == g_rdpdr_device[index].handle) return (SERIAL_DEVICE *) g_rdpdr_device[index].pdevice_data; } return NULL; } static RD_BOOL get_termios(SERIAL_DEVICE * pser_inf, RD_NTHANDLE serial_fd) { speed_t speed; struct termios *ptermios; ptermios = pser_inf->ptermios; if (tcgetattr(serial_fd, ptermios) == -1) return False; speed = cfgetispeed(ptermios); switch (speed) { #ifdef B75 case B75: pser_inf->baud_rate = 75; break; #endif #ifdef B110 case B110: pser_inf->baud_rate = 110; break; #endif #ifdef B134 case B134: pser_inf->baud_rate = 134; break; #endif #ifdef B150 case B150: pser_inf->baud_rate = 150; break; #endif #ifdef B300 case B300: pser_inf->baud_rate = 300; break; #endif #ifdef B600 case B600: pser_inf->baud_rate = 600; break; #endif #ifdef B1200 case B1200: pser_inf->baud_rate = 1200; break; #endif #ifdef B1800 case B1800: pser_inf->baud_rate = 1800; break; #endif #ifdef B2400 case B2400: pser_inf->baud_rate = 2400; break; #endif #ifdef B4800 case B4800: pser_inf->baud_rate = 4800; break; #endif #ifdef B9600 case B9600: pser_inf->baud_rate = 9600; break; #endif #ifdef B19200 case B19200: pser_inf->baud_rate = 19200; break; #endif #ifdef B38400 case B38400: pser_inf->baud_rate = 38400; break; #endif #ifdef B57600 case B57600: pser_inf->baud_rate = 57600; break; #endif #ifdef B115200 case B115200: pser_inf->baud_rate = 115200; break; #endif #ifdef B230400 case B230400: pser_inf->baud_rate = 230400; break; #endif #ifdef B460800 case B460800: pser_inf->baud_rate = 460800; break; #endif default: pser_inf->baud_rate = 9600; break; } speed = cfgetospeed(ptermios); pser_inf->dtr = (speed == B0) ? 0 : 1; pser_inf->stop_bits = (ptermios->c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BITS_1; pser_inf->parity = (ptermios->c_cflag & PARENB) ? ((ptermios->c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY) : NO_PARITY; switch (ptermios->c_cflag & CSIZE) { case CS5: pser_inf->word_length = 5; break; case CS6: pser_inf->word_length = 6; break; case CS7: pser_inf->word_length = 7; break; default: pser_inf->word_length = 8; break; } if (ptermios->c_cflag & CRTSCTS) { pser_inf->control = SERIAL_DTR_CONTROL | SERIAL_CTS_HANDSHAKE | SERIAL_ERROR_ABORT; } else { pser_inf->control = SERIAL_DTR_CONTROL | SERIAL_ERROR_ABORT; } pser_inf->xonoff = SERIAL_DSR_SENSITIVITY; if (ptermios->c_iflag & IXON) pser_inf->xonoff |= SERIAL_XON_HANDSHAKE; if (ptermios->c_iflag & IXOFF) pser_inf->xonoff |= SERIAL_XOFF_HANDSHAKE; pser_inf->chars[SERIAL_CHAR_XON] = ptermios->c_cc[VSTART]; pser_inf->chars[SERIAL_CHAR_XOFF] = ptermios->c_cc[VSTOP]; pser_inf->chars[SERIAL_CHAR_EOF] = ptermios->c_cc[VEOF]; pser_inf->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR]; pser_inf->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL]; return True; } static void set_termios(SERIAL_DEVICE * pser_inf, RD_NTHANDLE serial_fd) { speed_t speed; struct termios *ptermios; ptermios = pser_inf->ptermios; switch (pser_inf->baud_rate) { #ifdef B75 case 75: speed = B75; break; #endif #ifdef B110 case 110: speed = B110; break; #endif #ifdef B134 case 134: speed = B134; break; #endif #ifdef B150 case 150: speed = B150; break; #endif #ifdef B300 case 300: speed = B300; break; #endif #ifdef B600 case 600: speed = B600; break; #endif #ifdef B1200 case 1200: speed = B1200; break; #endif #ifdef B1800 case 1800: speed = B1800; break; #endif #ifdef B2400 case 2400: speed = B2400; break; #endif #ifdef B4800 case 4800: speed = B4800; break; #endif #ifdef B9600 case 9600: speed = B9600; break; #endif #ifdef B19200 case 19200: speed = B19200; break; #endif #ifdef B38400 case 38400: speed = B38400; break; #endif #ifdef B57600 case 57600: speed = B57600; break; #endif #ifdef B115200 case 115200: speed = B115200; break; #endif #ifdef B230400 case 230400: speed = B115200; break; #endif #ifdef B460800 case 460800: speed = B115200; break; #endif default: speed = B9600; break; } #ifdef CBAUD ptermios->c_cflag &= ~CBAUD; ptermios->c_cflag |= speed; #else /* on systems with separate ispeed and ospeed, we can remember the speed in ispeed while changing DTR with ospeed */ cfsetispeed(pser_inf->ptermios, speed); cfsetospeed(pser_inf->ptermios, pser_inf->dtr ? speed : 0); #endif ptermios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE | CRTSCTS); switch (pser_inf->stop_bits) { case STOP_BITS_2: ptermios->c_cflag |= CSTOPB; break; default: ptermios->c_cflag &= ~CSTOPB; break; } switch (pser_inf->parity) { case EVEN_PARITY: ptermios->c_cflag |= PARENB; break; case ODD_PARITY: ptermios->c_cflag |= PARENB | PARODD; break; case NO_PARITY: ptermios->c_cflag &= ~(PARENB | PARODD); break; } switch (pser_inf->word_length) { case 5: ptermios->c_cflag |= CS5; break; case 6: ptermios->c_cflag |= CS6; break; case 7: ptermios->c_cflag |= CS7; break; default: ptermios->c_cflag |= CS8; break; } #if 0 if (pser_inf->rts) ptermios->c_cflag |= CRTSCTS; else ptermios->c_cflag &= ~CRTSCTS; #endif if (pser_inf->control & SERIAL_CTS_HANDSHAKE) { ptermios->c_cflag |= CRTSCTS; } else { ptermios->c_cflag &= ~CRTSCTS; } if (pser_inf->xonoff & SERIAL_XON_HANDSHAKE) { ptermios->c_iflag |= IXON | IMAXBEL; } if (pser_inf->xonoff & SERIAL_XOFF_HANDSHAKE) { ptermios->c_iflag |= IXOFF | IMAXBEL; } if ((pser_inf->xonoff & (SERIAL_XOFF_HANDSHAKE | SERIAL_XON_HANDSHAKE)) == 0) { ptermios->c_iflag &= ~IXON; ptermios->c_iflag &= ~IXOFF; } ptermios->c_cc[VSTART] = pser_inf->chars[SERIAL_CHAR_XON]; ptermios->c_cc[VSTOP] = pser_inf->chars[SERIAL_CHAR_XOFF]; ptermios->c_cc[VEOF] = pser_inf->chars[SERIAL_CHAR_EOF]; ptermios->c_cc[VINTR] = pser_inf->chars[SERIAL_CHAR_BREAK]; ptermios->c_cc[VKILL] = pser_inf->chars[SERIAL_CHAR_ERROR]; tcsetattr(serial_fd, TCSANOW, ptermios); } /* Enumeration of devices from rdesktop.c */ /* returns numer of units found and initialized. */ /* optarg looks like ':com1=/dev/ttyS0' */ /* when it arrives to this function. */ /* :com1=/dev/ttyS0,com2=/dev/ttyS1 */ int serial_enum_devices(uint32 * id, char *optarg) { SERIAL_DEVICE *pser_inf; char *pos = optarg; char *pos2; int count = 0; /* skip the first colon */ optarg++; while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES) { /* Init data structures for device */ pser_inf = (SERIAL_DEVICE *) xmalloc(sizeof(SERIAL_DEVICE)); pser_inf->ptermios = (struct termios *) xmalloc(sizeof(struct termios)); memset(pser_inf->ptermios, 0, sizeof(struct termios)); pser_inf->pold_termios = (struct termios *) xmalloc(sizeof(struct termios)); memset(pser_inf->pold_termios, 0, sizeof(struct termios)); pos2 = next_arg(optarg, '='); strcpy(g_rdpdr_device[*id].name, optarg); toupper_str(g_rdpdr_device[*id].name); g_rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1); strcpy(g_rdpdr_device[*id].local_path, pos2); printf("SERIAL %s to %s\n", g_rdpdr_device[*id].name, g_rdpdr_device[*id].local_path); /* set device type */ g_rdpdr_device[*id].device_type = DEVICE_TYPE_SERIAL; g_rdpdr_device[*id].pdevice_data = (void *) pser_inf; count++; (*id)++; optarg = pos; } return count; } static RD_NTSTATUS serial_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * handle) { RD_NTHANDLE serial_fd; SERIAL_DEVICE *pser_inf; struct termios *ptermios; pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[device_id].pdevice_data; ptermios = pser_inf->ptermios; serial_fd = open(g_rdpdr_device[device_id].local_path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (serial_fd == -1) { perror("open"); return RD_STATUS_ACCESS_DENIED; } if (!get_termios(pser_inf, serial_fd)) { printf("INFO: SERIAL %s access denied\n", g_rdpdr_device[device_id].name); fflush(stdout); return RD_STATUS_ACCESS_DENIED; } /* Store handle for later use */ g_rdpdr_device[device_id].handle = serial_fd; /* some sane information */ DEBUG_SERIAL(("INFO: SERIAL %s to %s\nINFO: speed %u baud, stop bits %u, parity %u, word length %u bits, dtr %u, rts %u\n", g_rdpdr_device[device_id].name, g_rdpdr_device[device_id].local_path, pser_inf->baud_rate, pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length, pser_inf->dtr, pser_inf->rts)); pser_inf->ptermios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); pser_inf->ptermios->c_oflag &= ~OPOST; pser_inf->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); pser_inf->ptermios->c_cflag &= ~(CSIZE | PARENB); pser_inf->ptermios->c_cflag |= CS8; tcsetattr(serial_fd, TCSANOW, pser_inf->ptermios); pser_inf->event_txempty = 0; pser_inf->event_cts = 0; pser_inf->event_dsr = 0; pser_inf->event_rlsd = 0; pser_inf->event_pending = 0; *handle = serial_fd; /* all read and writes should be non blocking */ if (fcntl(*handle, F_SETFL, O_NONBLOCK) == -1) perror("fcntl"); pser_inf->read_total_timeout_constant = 5; return RD_STATUS_SUCCESS; } static RD_NTSTATUS serial_close(RD_NTHANDLE handle) { int i = get_device_index(handle); if (i >= 0) g_rdpdr_device[i].handle = 0; rdpdr_abort_io(handle, 0, RD_STATUS_TIMEOUT); close(handle); return RD_STATUS_SUCCESS; } static RD_NTSTATUS serial_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { long timeout; SERIAL_DEVICE *pser_inf; struct termios *ptermios; #ifdef WITH_DEBUG_SERIAL int bytes_inqueue; #endif timeout = 90; pser_inf = get_serial_info(handle); ptermios = pser_inf->ptermios; /* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout with requested read size */ if (pser_inf->read_total_timeout_multiplier | pser_inf->read_total_timeout_constant) { timeout = (pser_inf->read_total_timeout_multiplier * length + pser_inf->read_total_timeout_constant + 99) / 100; } else if (pser_inf->read_interval_timeout) { timeout = (pser_inf->read_interval_timeout * length + 99) / 100; } /* If a timeout is set, do a blocking read, which times out after some time. It will make rdesktop less responsive, but it will improve serial performance, by not reading one character at a time. */ if (timeout == 0) { ptermios->c_cc[VTIME] = 0; ptermios->c_cc[VMIN] = 0; } else { ptermios->c_cc[VTIME] = timeout; ptermios->c_cc[VMIN] = 1; } tcsetattr(handle, TCSANOW, ptermios); #if defined(WITH_DEBUG_SERIAL) && defined(TIOCINQ) ioctl(handle, TIOCINQ, &bytes_inqueue); DEBUG_SERIAL(("serial_read inqueue: %d expected %d\n", bytes_inqueue, length)); #endif *result = read(handle, data, length); #ifdef WITH_DEBUG_SERIAL DEBUG_SERIAL(("serial_read Bytes %d\n", *result)); if (*result > 0) hexdump(data, *result); #endif return RD_STATUS_SUCCESS; } static RD_NTSTATUS serial_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result) { SERIAL_DEVICE *pser_inf; pser_inf = get_serial_info(handle); *result = write(handle, data, length); if (*result > 0) pser_inf->event_txempty = *result; DEBUG_SERIAL(("serial_write length %d, offset %d result %d\n", length, offset, *result)); return RD_STATUS_SUCCESS; } static RD_NTSTATUS serial_device_control(RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out) { int purge_mask; uint32 result, modemstate; uint8 immediate; SERIAL_DEVICE *pser_inf; struct termios *ptermios; if ((request >> 16) != FILE_DEVICE_SERIAL_PORT) return RD_STATUS_INVALID_PARAMETER; pser_inf = get_serial_info(handle); ptermios = pser_inf->ptermios; /* extract operation */ request >>= 2; request &= 0xfff; switch (request) { case SERIAL_SET_BAUD_RATE: in_uint32_le(in, pser_inf->baud_rate); set_termios(pser_inf, handle); DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BAUD_RATE %d\n", pser_inf->baud_rate)); break; case SERIAL_GET_BAUD_RATE: out_uint32_le(out, pser_inf->baud_rate); DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_BAUD_RATE %d\n", pser_inf->baud_rate)); break; case SERIAL_SET_QUEUE_SIZE: in_uint32_le(in, pser_inf->queue_in_size); in_uint32_le(in, pser_inf->queue_out_size); DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_QUEUE_SIZE in %d out %d\n", pser_inf->queue_in_size, pser_inf->queue_out_size)); break; case SERIAL_SET_LINE_CONTROL: in_uint8(in, pser_inf->stop_bits); in_uint8(in, pser_inf->parity); in_uint8(in, pser_inf->word_length); set_termios(pser_inf, handle); DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_LINE_CONTROL stop %d parity %d word %d\n", pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length)); break; case SERIAL_GET_LINE_CONTROL: DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_LINE_CONTROL\n")); out_uint8(out, pser_inf->stop_bits); out_uint8(out, pser_inf->parity); out_uint8(out, pser_inf->word_length); break; case SERIAL_IMMEDIATE_CHAR: DEBUG_SERIAL(("serial_ioctl -> SERIAL_IMMEDIATE_CHAR\n")); in_uint8(in, immediate); serial_write(handle, &immediate, 1, 0, &result); break; case SERIAL_CONFIG_SIZE: DEBUG_SERIAL(("serial_ioctl -> SERIAL_CONFIG_SIZE\n")); out_uint32_le(out, 0); break; case SERIAL_GET_CHARS: DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_CHARS\n")); out_uint8a(out, pser_inf->chars, 6); break; case SERIAL_SET_CHARS: DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_CHARS\n")); in_uint8a(in, pser_inf->chars, 6); #ifdef WITH_DEBUG_SERIAL hexdump(pser_inf->chars, 6); #endif set_termios(pser_inf, handle); break; case SERIAL_GET_HANDFLOW: DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_HANDFLOW\n")); get_termios(pser_inf, handle); out_uint32_le(out, pser_inf->control); out_uint32_le(out, pser_inf->xonoff); /* Xon/Xoff */ out_uint32_le(out, pser_inf->onlimit); out_uint32_le(out, pser_inf->offlimit); break; case SERIAL_SET_HANDFLOW: in_uint32_le(in, pser_inf->control); in_uint32_le(in, pser_inf->xonoff); in_uint32_le(in, pser_inf->onlimit); in_uint32_le(in, pser_inf->offlimit); DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_HANDFLOW %x %x %x %x\n", pser_inf->control, pser_inf->xonoff, pser_inf->onlimit, pser_inf->onlimit)); set_termios(pser_inf, handle); break; case SERIAL_SET_TIMEOUTS: in_uint32(in, pser_inf->read_interval_timeout); in_uint32(in, pser_inf->read_total_timeout_multiplier); in_uint32(in, pser_inf->read_total_timeout_constant); in_uint32(in, pser_inf->write_total_timeout_multiplier); in_uint32(in, pser_inf->write_total_timeout_constant); DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_TIMEOUTS read timeout %d %d %d\n", pser_inf->read_interval_timeout, pser_inf->read_total_timeout_multiplier, pser_inf->read_total_timeout_constant)); break; case SERIAL_GET_TIMEOUTS: DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_TIMEOUTS read timeout %d %d %d\n", pser_inf->read_interval_timeout, pser_inf->read_total_timeout_multiplier, pser_inf->read_total_timeout_constant)); out_uint32(out, pser_inf->read_interval_timeout); out_uint32(out, pser_inf->read_total_timeout_multiplier); out_uint32(out, pser_inf->read_total_timeout_constant); out_uint32(out, pser_inf->write_total_timeout_multiplier); out_uint32(out, pser_inf->write_total_timeout_constant); break; case SERIAL_GET_WAIT_MASK: DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_WAIT_MASK %X\n", pser_inf->wait_mask)); out_uint32(out, pser_inf->wait_mask); break; case SERIAL_SET_WAIT_MASK: in_uint32(in, pser_inf->wait_mask); DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_WAIT_MASK %X\n", pser_inf->wait_mask)); break; case SERIAL_SET_DTR: DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_DTR\n")); ioctl(handle, TIOCMGET, &result); result |= TIOCM_DTR; ioctl(handle, TIOCMSET, &result); pser_inf->dtr = 1; break; case SERIAL_CLR_DTR: DEBUG_SERIAL(("serial_ioctl -> SERIAL_CLR_DTR\n")); ioctl(handle, TIOCMGET, &result); result &= ~TIOCM_DTR; ioctl(handle, TIOCMSET, &result); pser_inf->dtr = 0; break; case SERIAL_SET_RTS: DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_RTS\n")); ioctl(handle, TIOCMGET, &result); result |= TIOCM_RTS; ioctl(handle, TIOCMSET, &result); pser_inf->rts = 1; break; case SERIAL_CLR_RTS: DEBUG_SERIAL(("serial_ioctl -> SERIAL_CLR_RTS\n")); ioctl(handle, TIOCMGET, &result); result &= ~TIOCM_RTS; ioctl(handle, TIOCMSET, &result); pser_inf->rts = 0; break; case SERIAL_GET_MODEMSTATUS: modemstate = 0; #ifdef TIOCMGET ioctl(handle, TIOCMGET, &result); if (result & TIOCM_CTS) modemstate |= SERIAL_MS_CTS; if (result & TIOCM_DSR) modemstate |= SERIAL_MS_DSR; if (result & TIOCM_RNG) modemstate |= SERIAL_MS_RNG; if (result & TIOCM_CAR) modemstate |= SERIAL_MS_CAR; if (result & TIOCM_DTR) modemstate |= SERIAL_MS_DTR; if (result & TIOCM_RTS) modemstate |= SERIAL_MS_RTS; #endif DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_MODEMSTATUS %X\n", modemstate)); out_uint32_le(out, modemstate); break; case SERIAL_GET_COMMSTATUS: out_uint32_le(out, 0); /* Errors */ out_uint32_le(out, 0); /* Hold reasons */ result = 0; #ifdef TIOCINQ ioctl(handle, TIOCINQ, &result); #endif out_uint32_le(out, result); /* Amount in in queue */ if (result) DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_COMMSTATUS in queue %d\n", result)); result = 0; #ifdef TIOCOUTQ ioctl(handle, TIOCOUTQ, &result); #endif out_uint32_le(out, result); /* Amount in out queue */ if (result) DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_COMMSTATUS out queue %d\n", result)); out_uint8(out, 0); /* EofReceived */ out_uint8(out, 0); /* WaitForImmediate */ break; case SERIAL_PURGE: in_uint32(in, purge_mask); DEBUG_SERIAL(("serial_ioctl -> SERIAL_PURGE purge_mask %X\n", purge_mask)); if ((purge_mask & SERIAL_PURGE_TXCLEAR) && (purge_mask & SERIAL_PURGE_RXCLEAR)) tcflush(handle, TCIOFLUSH); else if (purge_mask & SERIAL_PURGE_TXCLEAR) tcflush(handle, TCOFLUSH); else if (purge_mask & SERIAL_PURGE_RXCLEAR) tcflush(handle, TCIFLUSH); if (purge_mask & SERIAL_PURGE_TXABORT) rdpdr_abort_io(handle, 4, RD_STATUS_CANCELLED); if (purge_mask & SERIAL_PURGE_RXABORT) rdpdr_abort_io(handle, 3, RD_STATUS_CANCELLED); break; case SERIAL_WAIT_ON_MASK: DEBUG_SERIAL(("serial_ioctl -> SERIAL_WAIT_ON_MASK %X\n", pser_inf->wait_mask)); pser_inf->event_pending = 1; if (serial_get_event(handle, &result)) { DEBUG_SERIAL(("WAIT end event = %x\n", result)); out_uint32_le(out, result); break; } return RD_STATUS_PENDING; break; case SERIAL_SET_BREAK_ON: DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BREAK_ON\n")); tcsendbreak(handle, 0); break; case SERIAL_RESET_DEVICE: DEBUG_SERIAL(("serial_ioctl -> SERIAL_RESET_DEVICE\n")); break; case SERIAL_SET_BREAK_OFF: DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BREAK_OFF\n")); break; case SERIAL_SET_XOFF: DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_XOFF\n")); break; case SERIAL_SET_XON: DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_XON\n")); tcflow(handle, TCION); break; default: unimpl("SERIAL IOCTL %d\n", request); return RD_STATUS_INVALID_PARAMETER; } return RD_STATUS_SUCCESS; } RD_BOOL serial_get_event(RD_NTHANDLE handle, uint32 * result) { int index; SERIAL_DEVICE *pser_inf; int bytes; RD_BOOL ret = False; *result = 0; index = get_device_index(handle); if (index < 0) return False; #ifdef TIOCINQ pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[index].pdevice_data; ioctl(handle, TIOCINQ, &bytes); if (bytes > 0) { DEBUG_SERIAL(("serial_get_event Bytes %d\n", bytes)); if (bytes > pser_inf->event_rlsd) { pser_inf->event_rlsd = bytes; if (pser_inf->wait_mask & SERIAL_EV_RLSD) { DEBUG_SERIAL(("Event -> SERIAL_EV_RLSD \n")); *result |= SERIAL_EV_RLSD; ret = True; } } if ((bytes > 1) && (pser_inf->wait_mask & SERIAL_EV_RXFLAG)) { DEBUG_SERIAL(("Event -> SERIAL_EV_RXFLAG Bytes %d\n", bytes)); *result |= SERIAL_EV_RXFLAG; ret = True; } if ((pser_inf->wait_mask & SERIAL_EV_RXCHAR)) { DEBUG_SERIAL(("Event -> SERIAL_EV_RXCHAR Bytes %d\n", bytes)); *result |= SERIAL_EV_RXCHAR; ret = True; } } else { pser_inf->event_rlsd = 0; } #endif #ifdef TIOCOUTQ ioctl(handle, TIOCOUTQ, &bytes); if ((bytes == 0) && (pser_inf->event_txempty > 0) && (pser_inf->wait_mask & SERIAL_EV_TXEMPTY)) { DEBUG_SERIAL(("Event -> SERIAL_EV_TXEMPTY\n")); *result |= SERIAL_EV_TXEMPTY; ret = True; } pser_inf->event_txempty = bytes; #endif ioctl(handle, TIOCMGET, &bytes); if ((bytes & TIOCM_DSR) != pser_inf->event_dsr) { pser_inf->event_dsr = bytes & TIOCM_DSR; if (pser_inf->wait_mask & SERIAL_EV_DSR) { DEBUG_SERIAL(("event -> SERIAL_EV_DSR %s\n", (bytes & TIOCM_DSR) ? "ON" : "OFF")); *result |= SERIAL_EV_DSR; ret = True; } } if ((bytes & TIOCM_CTS) != pser_inf->event_cts) { pser_inf->event_cts = bytes & TIOCM_CTS; if (pser_inf->wait_mask & SERIAL_EV_CTS) { DEBUG_SERIAL((" EVENT-> SERIAL_EV_CTS %s\n", (bytes & TIOCM_CTS) ? "ON" : "OFF")); *result |= SERIAL_EV_CTS; ret = True; } } if (ret) pser_inf->event_pending = 0; return ret; } /* Read timeout for a given file descripter (device) when adding fd's to select() */ RD_BOOL serial_get_timeout(RD_NTHANDLE handle, uint32 length, uint32 * timeout, uint32 * itv_timeout) { int index; SERIAL_DEVICE *pser_inf; index = get_device_index(handle); if (index < 0) return True; if (g_rdpdr_device[index].device_type != DEVICE_TYPE_SERIAL) { return False; } pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[index].pdevice_data; *timeout = pser_inf->read_total_timeout_multiplier * length + pser_inf->read_total_timeout_constant; *itv_timeout = pser_inf->read_interval_timeout; return True; } DEVICE_FNS serial_fns = { serial_create, serial_close, serial_read, serial_write, serial_device_control }; rdesktop-1.8.3/ssl.c0000664000770100510440000001251012041500663013236 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Secure sockets abstraction layer Copyright (C) Matthew Chapman 1999-2008 Copyright (C) Jay Sorg 2006-2008 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 3 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, see . */ #include "rdesktop.h" #include "ssl.h" void rdssl_sha1_init(RDSSL_SHA1 * sha1) { SHA1_Init(sha1); } void rdssl_sha1_update(RDSSL_SHA1 * sha1, uint8 * data, uint32 len) { SHA1_Update(sha1, data, len); } void rdssl_sha1_final(RDSSL_SHA1 * sha1, uint8 * out_data) { SHA1_Final(out_data, sha1); } void rdssl_md5_init(RDSSL_MD5 * md5) { MD5_Init(md5); } void rdssl_md5_update(RDSSL_MD5 * md5, uint8 * data, uint32 len) { MD5_Update(md5, data, len); } void rdssl_md5_final(RDSSL_MD5 * md5, uint8 * out_data) { MD5_Final(out_data, md5); } void rdssl_rc4_set_key(RDSSL_RC4 * rc4, uint8 * key, uint32 len) { RC4_set_key(rc4, len, key); } void rdssl_rc4_crypt(RDSSL_RC4 * rc4, uint8 * in_data, uint8 * out_data, uint32 len) { RC4(rc4, len, in_data, out_data); } static void reverse(uint8 * p, int len) { int i, j; uint8 temp; for (i = 0, j = len - 1; i < j; i++, j--) { temp = p[i]; p[i] = p[j]; p[j] = temp; } } void rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, uint8 * exponent) { BN_CTX *ctx; BIGNUM mod, exp, x, y; uint8 inr[SEC_MAX_MODULUS_SIZE]; int outlen; reverse(modulus, modulus_size); reverse(exponent, SEC_EXPONENT_SIZE); memcpy(inr, in, len); reverse(inr, len); ctx = BN_CTX_new(); BN_init(&mod); BN_init(&exp); BN_init(&x); BN_init(&y); BN_bin2bn(modulus, modulus_size, &mod); BN_bin2bn(exponent, SEC_EXPONENT_SIZE, &exp); BN_bin2bn(inr, len, &x); BN_mod_exp(&y, &x, &exp, &mod, ctx); outlen = BN_bn2bin(&y, out); reverse(out, outlen); if (outlen < (int) modulus_size) memset(out + outlen, 0, modulus_size - outlen); BN_free(&y); BN_clear_free(&x); BN_free(&exp); BN_free(&mod); BN_CTX_free(ctx); } /* returns newly allocated RDSSL_CERT or NULL */ RDSSL_CERT * rdssl_cert_read(uint8 * data, uint32 len) { /* this will move the data pointer but we don't care, we don't use it again */ return d2i_X509(NULL, (D2I_X509_CONST unsigned char **) &data, len); } void rdssl_cert_free(RDSSL_CERT * cert) { X509_free(cert); } /* returns newly allocated RDSSL_RKEY or NULL */ RDSSL_RKEY * rdssl_cert_to_rkey(RDSSL_CERT * cert, uint32 * key_len) { EVP_PKEY *epk = NULL; RDSSL_RKEY *lkey; int nid; /* By some reason, Microsoft sets the OID of the Public RSA key to the oid for "MD5 with RSA Encryption" instead of "RSA Encryption" Kudos to Richard Levitte for the following (. intiutive .) lines of code that resets the OID and let's us extract the key. */ nid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); if ((nid == NID_md5WithRSAEncryption) || (nid == NID_shaWithRSAEncryption)) { DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n")); ASN1_OBJECT_free(cert->cert_info->key->algor->algorithm); cert->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption); } epk = X509_get_pubkey(cert); if (NULL == epk) { error("Failed to extract public key from certificate\n"); return NULL; } lkey = RSAPublicKey_dup(EVP_PKEY_get1_RSA(epk)); EVP_PKEY_free(epk); *key_len = RSA_size(lkey); return lkey; } /* returns boolean */ RD_BOOL rdssl_certs_ok(RDSSL_CERT * server_cert, RDSSL_CERT * cacert) { /* Currently, we don't use the CA Certificate. FIXME: *) Verify the server certificate (server_cert) with the CA certificate. *) Store the CA Certificate with the hostname of the server we are connecting to as key, and compare it when we connect the next time, in order to prevent MITM-attacks. */ return True; } int rdssl_cert_print_fp(FILE * fp, RDSSL_CERT * cert) { return X509_print_fp(fp, cert); } void rdssl_rkey_free(RDSSL_RKEY * rkey) { RSA_free(rkey); } /* returns error */ int rdssl_rkey_get_exp_mod(RDSSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus, uint32 max_mod_len) { int len; if ((BN_num_bytes(rkey->e) > (int) max_exp_len) || (BN_num_bytes(rkey->n) > (int) max_mod_len)) { return 1; } len = BN_bn2bin(rkey->e, exponent); reverse(exponent, len); len = BN_bn2bin(rkey->n, modulus); reverse(modulus, len); return 0; } /* returns boolean */ RD_BOOL rdssl_sig_ok(uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len, uint8 * signature, uint32 sig_len) { /* Currently, we don't check the signature FIXME: */ return True; } void rdssl_hmac_md5(const void *key, int key_len, const unsigned char *msg, int msg_len, unsigned char *md) { HMAC_CTX ctx; HMAC_CTX_init(&ctx); HMAC(EVP_md5(), key, key_len, msg, msg_len, md, NULL); HMAC_CTX_cleanup(&ctx); } rdesktop-1.8.3/tcp.c0000664000770100510440000003012012207655115013227 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - TCP layer Copyright (C) Matthew Chapman 1999-2008 Copyright 2005-2011 Peter Astrand for Cendio AB Copyright 2012-2013 Henrik Andersson for Cendio AB 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 3 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, see . */ #ifndef _WIN32 #include /* select read write close */ #include /* socket connect setsockopt */ #include /* timeval */ #include /* gethostbyname */ #include /* sockaddr_in */ #include /* TCP_NODELAY */ #include /* inet_addr */ #include /* errno */ #endif #include #include #include #include "rdesktop.h" #ifdef _WIN32 #define socklen_t int #define TCP_CLOSE(_sck) closesocket(_sck) #define TCP_STRERROR "tcp error" #define TCP_BLOCKS (WSAGetLastError() == WSAEWOULDBLOCK) #else #define TCP_CLOSE(_sck) close(_sck) #define TCP_STRERROR strerror(errno) #define TCP_BLOCKS (errno == EWOULDBLOCK) #endif #ifndef INADDR_NONE #define INADDR_NONE ((unsigned long) -1) #endif #ifdef WITH_SCARD #define STREAM_COUNT 8 #else #define STREAM_COUNT 1 #endif static RD_BOOL g_ssl_initialized = False; static SSL *g_ssl = NULL; static SSL_CTX *g_ssl_ctx = NULL; static int g_sock; static RD_BOOL g_run_ui = False; static struct stream g_in; static struct stream g_out[STREAM_COUNT]; int g_tcp_port_rdp = TCP_PORT_RDP; extern RD_BOOL g_user_quit; extern RD_BOOL g_network_error; extern RD_BOOL g_reconnect_loop; /* wait till socket is ready to write or timeout */ static RD_BOOL tcp_can_send(int sck, int millis) { fd_set wfds; struct timeval time; int sel_count; time.tv_sec = millis / 1000; time.tv_usec = (millis * 1000) % 1000000; FD_ZERO(&wfds); FD_SET(sck, &wfds); sel_count = select(sck + 1, 0, &wfds, 0, &time); if (sel_count > 0) { return True; } return False; } /* Initialise TCP transport data packet */ STREAM tcp_init(uint32 maxlen) { static int cur_stream_id = 0; STREAM result = NULL; #ifdef WITH_SCARD scard_lock(SCARD_LOCK_TCP); #endif result = &g_out[cur_stream_id]; cur_stream_id = (cur_stream_id + 1) % STREAM_COUNT; if (maxlen > result->size) { result->data = (uint8 *) xrealloc(result->data, maxlen); result->size = maxlen; } result->p = result->data; result->end = result->data + result->size; #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_TCP); #endif return result; } /* Send TCP transport data packet */ void tcp_send(STREAM s) { int ssl_err; int length = s->end - s->data; int sent, total = 0; if (g_network_error == True) return; #ifdef WITH_SCARD scard_lock(SCARD_LOCK_TCP); #endif while (total < length) { if (g_ssl) { sent = SSL_write(g_ssl, s->data + total, length - total); if (sent <= 0) { ssl_err = SSL_get_error(g_ssl, sent); if (sent < 0 && (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE)) { tcp_can_send(g_sock, 100); sent = 0; } else { #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_TCP); #endif error("SSL_write: %d (%s)\n", ssl_err, TCP_STRERROR); g_network_error = True; return; } } } else { sent = send(g_sock, s->data + total, length - total, 0); if (sent <= 0) { if (sent == -1 && TCP_BLOCKS) { tcp_can_send(g_sock, 100); sent = 0; } else { #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_TCP); #endif error("send: %s\n", TCP_STRERROR); g_network_error = True; return; } } } total += sent; } #ifdef WITH_SCARD scard_unlock(SCARD_LOCK_TCP); #endif } /* Receive a message on the TCP layer */ STREAM tcp_recv(STREAM s, uint32 length) { uint32 new_length, end_offset, p_offset; int rcvd = 0, ssl_err; if (g_network_error == True) return NULL; if (s == NULL) { /* read into "new" stream */ if (length > g_in.size) { g_in.data = (uint8 *) xrealloc(g_in.data, length); g_in.size = length; } g_in.end = g_in.p = g_in.data; s = &g_in; } else { /* append to existing stream */ new_length = (s->end - s->data) + length; if (new_length > s->size) { p_offset = s->p - s->data; end_offset = s->end - s->data; s->data = (uint8 *) xrealloc(s->data, new_length); s->size = new_length; s->p = s->data + p_offset; s->end = s->data + end_offset; } } while (length > 0) { if ((!g_ssl || SSL_pending(g_ssl) <= 0) && g_run_ui) { if (!ui_select(g_sock)) { /* User quit */ g_user_quit = True; return NULL; } } if (g_ssl) { rcvd = SSL_read(g_ssl, s->end, length); ssl_err = SSL_get_error(g_ssl, rcvd); if (ssl_err == SSL_ERROR_SSL) { if (SSL_get_shutdown(g_ssl) & SSL_RECEIVED_SHUTDOWN) { error("Remote peer initiated ssl shutdown.\n"); return NULL; } ERR_print_errors_fp(stdout); g_network_error = True; return NULL; } if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) { rcvd = 0; } else if (ssl_err != SSL_ERROR_NONE) { error("SSL_read: %d (%s)\n", ssl_err, TCP_STRERROR); g_network_error = True; return NULL; } } else { rcvd = recv(g_sock, s->end, length, 0); if (rcvd < 0) { if (rcvd == -1 && TCP_BLOCKS) { rcvd = 0; } else { error("recv: %s\n", TCP_STRERROR); g_network_error = True; return NULL; } } else if (rcvd == 0) { error("Connection closed\n"); return NULL; } } s->end += rcvd; length -= rcvd; } return s; } /* Establish a SSL/TLS 1.0 connection */ RD_BOOL tcp_tls_connect(void) { int err; long options; if (!g_ssl_initialized) { SSL_load_error_strings(); SSL_library_init(); g_ssl_initialized = True; } /* create process context */ if (g_ssl_ctx == NULL) { g_ssl_ctx = SSL_CTX_new(TLSv1_client_method()); if (g_ssl_ctx == NULL) { error("tcp_tls_connect: SSL_CTX_new() failed to create TLS v1.0 context\n"); goto fail; } options = 0; #ifdef SSL_OP_NO_COMPRESSION options |= SSL_OP_NO_COMPRESSION; #endif // __SSL_OP_NO_COMPRESSION options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; SSL_CTX_set_options(g_ssl_ctx, options); } /* free old connection */ if (g_ssl) SSL_free(g_ssl); /* create new ssl connection */ g_ssl = SSL_new(g_ssl_ctx); if (g_ssl == NULL) { error("tcp_tls_connect: SSL_new() failed\n"); goto fail; } if (SSL_set_fd(g_ssl, g_sock) < 1) { error("tcp_tls_connect: SSL_set_fd() failed\n"); goto fail; } do { err = SSL_connect(g_ssl); } while (SSL_get_error(g_ssl, err) == SSL_ERROR_WANT_READ); if (err < 0) { ERR_print_errors_fp(stdout); goto fail; } return True; fail: if (g_ssl) SSL_free(g_ssl); if (g_ssl_ctx) SSL_CTX_free(g_ssl_ctx); g_ssl = NULL; g_ssl_ctx = NULL; return False; } /* Get public key from server of TLS 1.0 connection */ RD_BOOL tcp_tls_get_server_pubkey(STREAM s) { X509 *cert = NULL; EVP_PKEY *pkey = NULL; s->data = s->p = NULL; s->size = 0; if (g_ssl == NULL) goto out; cert = SSL_get_peer_certificate(g_ssl); if (cert == NULL) { error("tcp_tls_get_server_pubkey: SSL_get_peer_certificate() failed\n"); goto out; } pkey = X509_get_pubkey(cert); if (pkey == NULL) { error("tcp_tls_get_server_pubkey: X509_get_pubkey() failed\n"); goto out; } s->size = i2d_PublicKey(pkey, NULL); if (s->size < 1) { error("tcp_tls_get_server_pubkey: i2d_PublicKey() failed\n"); goto out; } s->data = s->p = xmalloc(s->size); i2d_PublicKey(pkey, &s->p); s->p = s->data; s->end = s->p + s->size; out: if (cert) X509_free(cert); if (pkey) EVP_PKEY_free(pkey); return (s->size != 0); } /* Establish a connection on the TCP layer */ RD_BOOL tcp_connect(char *server) { socklen_t option_len; uint32 option_value; int i; #ifdef IPv6 int n; struct addrinfo hints, *res, *ressave; char tcp_port_rdp_s[10]; snprintf(tcp_port_rdp_s, 10, "%d", g_tcp_port_rdp); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res))) { error("getaddrinfo: %s\n", gai_strerror(n)); return False; } ressave = res; g_sock = -1; while (res) { g_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (!(g_sock < 0)) { if (connect(g_sock, res->ai_addr, res->ai_addrlen) == 0) break; TCP_CLOSE(g_sock); g_sock = -1; } res = res->ai_next; } freeaddrinfo(ressave); if (g_sock == -1) { error("%s: unable to connect\n", server); return False; } #else /* no IPv6 support */ struct hostent *nslookup; struct sockaddr_in servaddr; if ((nslookup = gethostbyname(server)) != NULL) { memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr)); } else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE) { error("%s: unable to resolve host\n", server); return False; } if ((g_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { error("socket: %s\n", TCP_STRERROR); return False; } servaddr.sin_family = AF_INET; servaddr.sin_port = htons((uint16) g_tcp_port_rdp); if (connect(g_sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0) { if (!g_reconnect_loop) error("connect: %s\n", TCP_STRERROR); TCP_CLOSE(g_sock); g_sock = -1; return False; } #endif /* IPv6 */ option_value = 1; option_len = sizeof(option_value); setsockopt(g_sock, IPPROTO_TCP, TCP_NODELAY, (void *) &option_value, option_len); /* receive buffer must be a least 16 K */ if (getsockopt(g_sock, SOL_SOCKET, SO_RCVBUF, (void *) &option_value, &option_len) == 0) { if (option_value < (1024 * 16)) { option_value = 1024 * 16; option_len = sizeof(option_value); setsockopt(g_sock, SOL_SOCKET, SO_RCVBUF, (void *) &option_value, option_len); } } g_in.size = 4096; g_in.data = (uint8 *) xmalloc(g_in.size); for (i = 0; i < STREAM_COUNT; i++) { g_out[i].size = 4096; g_out[i].data = (uint8 *) xmalloc(g_out[i].size); } return True; } /* Disconnect on the TCP layer */ void tcp_disconnect(void) { if (g_ssl) { if (!g_network_error) (void) SSL_shutdown(g_ssl); SSL_free(g_ssl); g_ssl = NULL; SSL_CTX_free(g_ssl_ctx); g_ssl_ctx = NULL; } TCP_CLOSE(g_sock); g_sock = -1; } char * tcp_get_address() { static char ipaddr[32]; struct sockaddr_in sockaddr; socklen_t len = sizeof(sockaddr); if (getsockname(g_sock, (struct sockaddr *) &sockaddr, &len) == 0) { uint8 *ip = (uint8 *) & sockaddr.sin_addr; sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); } else strcpy(ipaddr, "127.0.0.1"); return ipaddr; } RD_BOOL tcp_is_connected() { struct sockaddr_in sockaddr; socklen_t len = sizeof(sockaddr); if (getpeername(g_sock, (struct sockaddr *) &sockaddr, &len)) return True; return False; } /* reset the state of the tcp layer */ /* Support for Session Directory */ void tcp_reset_state(void) { int i; /* Clear the incoming stream */ if (g_in.data != NULL) xfree(g_in.data); g_in.p = NULL; g_in.end = NULL; g_in.data = NULL; g_in.size = 0; g_in.iso_hdr = NULL; g_in.mcs_hdr = NULL; g_in.sec_hdr = NULL; g_in.rdp_hdr = NULL; g_in.channel_hdr = NULL; /* Clear the outgoing stream(s) */ for (i = 0; i < STREAM_COUNT; i++) { if (g_out[i].data != NULL) xfree(g_out[i].data); g_out[i].p = NULL; g_out[i].end = NULL; g_out[i].data = NULL; g_out[i].size = 0; g_out[i].iso_hdr = NULL; g_out[i].mcs_hdr = NULL; g_out[i].sec_hdr = NULL; g_out[i].rdp_hdr = NULL; g_out[i].channel_hdr = NULL; } } void tcp_run_ui(RD_BOOL run) { g_run_ui = run; } rdesktop-1.8.3/utils.c0000664000770100510440000001003512077232136013603 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Generic utility functions Copyright 2013 Henrik Andersson for Cendio AB 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 3 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, see . */ #include #include #include #include #ifdef HAVE_ICONV_H #include #endif #include "rdesktop.h" #ifdef HAVE_ICONV extern char g_codepage[16]; static RD_BOOL g_iconv_works = True; #endif char * utils_string_escape(const char *str) { const char *p; char *pe, *e, esc[4]; size_t es; int cnt; /* count indices */ cnt = 0; p = str; while (*(p++) != '\0') if ((unsigned char) *p < 32 || *p == '%') cnt++; /* if no characters needs escaping return copy of str */ if (cnt == 0) return strdup(str); /* allocate new mem for result */ es = strlen(str) + (cnt * 3) + 1; pe = e = xmalloc(es); memset(e, 0, es); p = str; while (*p != '\0') { if ((unsigned char) *p < 32 || *p == '%') { snprintf(esc, 4, "%%%02X", *p); memcpy(pe, esc, 3); pe += 3; } else { *pe = *p; pe++; } p++; } return e; } char * utils_string_unescape(const char *str) { char *ns, *ps, *pd, c; ns = xmalloc(strlen(str) + 1); memcpy(ns, str, strlen(str) + 1); ps = pd = ns; while (*ps != '\0') { /* check if found escaped character */ if (ps[0] == '%') { if (sscanf(ps, "%%%2hhX", &c) == 1) { pd[0] = c; ps += 3; pd++; continue; } } /* just copy over the char */ *pd = *ps; ps++; pd++; } pd[0] = '\0'; return ns; } int utils_mkdir_safe(const char *path, int mask) { int res = 0; struct stat st; res = stat(path, &st); if (res == -1) return mkdir(path, mask); if (!S_ISDIR(st.st_mode)) { errno = EEXIST; return -1; } return 0; } int utils_mkdir_p(const char *path, int mask) { int res; char *ptok; char pt[PATH_MAX]; char bp[PATH_MAX]; if (!path || strlen(path) == 0) { errno = EINVAL; return -1; } if (strlen(path) > PATH_MAX) { errno = E2BIG; return -1; } res = 0; pt[0] = bp[0] = '\0'; strcpy(bp, path); ptok = strtok(bp, "/"); if (ptok == NULL) return utils_mkdir_safe(path, mask); do { if (ptok != bp) strcat(pt, "/"); strcat(pt, ptok); res = utils_mkdir_safe(pt, mask); if (res != 0) return res; } while ((ptok = strtok(NULL, "/")) != NULL); return 0; } /* Convert from system locale string to utf-8 */ int utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os) { #ifdef HAVE_ICONV static iconv_t *iconv_h = (iconv_t) - 1; if (strncmp(g_codepage, "UTF-8", strlen("UTF-8")) == 0) goto pass_trough_as_is; if (g_iconv_works == False) goto pass_trough_as_is; /* if not already initialize */ if (iconv_h == (iconv_t) - 1) { if ((iconv_h = iconv_open("UTF-8", g_codepage)) == (iconv_t) - 1) { warning("utils_string_to_utf8: iconv_open[%s -> %s] fail %p\n", g_codepage, "UTF-8", iconv_h); g_iconv_works = False; goto pass_trough_as_is; } } /* convert string */ if (iconv(iconv_h, (ICONV_CONST char **) &src, &is, &dest, &os) == (size_t) - 1) { iconv_close(iconv_h); iconv_h = (iconv_t) - 1; warning("utils_string_to_utf8: iconv(1) fail, errno %d\n", errno); g_iconv_works = False; goto pass_trough_as_is; } /* Out couldn't hold the entire convertion */ if (is != 0) return -1; #endif pass_trough_as_is: /* can dest hold strcpy of src */ if (os < (strlen(src) + 1)) return -1; memcpy(dest, src, strlen(src) + 1); return 0; } rdesktop-1.8.3/xclip.c0000664000770100510440000010721111704742441013566 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Protocol services - Clipboard functions Copyright 2003-2008 Erik Forsberg for Cendio AB Copyright (C) Matthew Chapman 2003-2008 Copyright 2006-2011 Pierre Ossman for Cendio AB 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 3 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, see . */ #include #include #include "rdesktop.h" /* To gain better understanding of this code, one could be assisted by the following documents: - Inter-Client Communication Conventions Manual (ICCCM) HTML: http://tronche.com/gui/x/icccm/ PDF: http://ftp.xfree86.org/pub/XFree86/4.5.0/doc/PDF/icccm.pdf - MSDN: Clipboard Formats http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/dataexchange/clipboard/clipboardformats.asp */ #ifdef HAVE_ICONV #ifdef HAVE_LANGINFO_H #ifdef HAVE_ICONV_H #include #include #define USE_UNICODE_CLIPBOARD #endif #endif #endif #ifdef USE_UNICODE_CLIPBOARD #define RDP_CF_TEXT CF_UNICODETEXT #else #define RDP_CF_TEXT CF_TEXT #endif #define MAX_TARGETS 8 extern Display *g_display; extern Window g_wnd; extern Time g_last_gesturetime; extern RD_BOOL g_rdpclip; /* Mode of operation. - Auto: Look at both PRIMARY and CLIPBOARD and use the most recent. - Non-auto: Look at just CLIPBOARD. */ static RD_BOOL auto_mode = True; /* Atoms of the two X selections we're dealing with: CLIPBOARD (explicit-copy) and PRIMARY (selection-copy) */ static Atom clipboard_atom, primary_atom; /* Atom of the TARGETS clipboard target */ static Atom targets_atom; /* Atom of the TIMESTAMP clipboard target */ static Atom timestamp_atom; /* Atom _RDESKTOP_CLIPBOARD_TARGET which is used as the 'property' argument in XConvertSelection calls: This is the property of our window into which XConvertSelection will store the received clipboard data. */ static Atom rdesktop_clipboard_target_atom; /* Atoms _RDESKTOP_PRIMARY_TIMESTAMP_TARGET and _RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET are used to store the timestamps for when a window got ownership of the selections. We use these to determine which is more recent and should be used. */ static Atom rdesktop_primary_timestamp_target_atom, rdesktop_clipboard_timestamp_target_atom; /* Storage for timestamps since we get them in two separate notifications. */ static Time primary_timestamp, clipboard_timestamp; /* Clipboard target for getting a list of native Windows clipboard formats. The presence of this target indicates that the selection owner is another rdesktop. */ static Atom rdesktop_clipboard_formats_atom; /* The clipboard target (X jargon for "clipboard format") for rdesktop-to-rdesktop interchange of Windows native clipboard data. The requestor must supply the desired native Windows clipboard format in the associated property. */ static Atom rdesktop_native_atom; /* Local copy of the list of native Windows clipboard formats. */ static uint8 *formats_data = NULL; static uint32 formats_data_length = 0; /* We need to know when another rdesktop process gets or loses ownership of a selection. Without XFixes we do this by touching a property on the root window which will generate PropertyNotify notifications. */ static Atom rdesktop_selection_notify_atom; /* State variables that indicate if we're currently probing the targets of the selection owner. reprobe_selections indicate that the ownership changed in the middle of the current probe so it should be restarted. */ static RD_BOOL probing_selections, reprobe_selections; /* Atoms _RDESKTOP_PRIMARY_OWNER and _RDESKTOP_CLIPBOARD_OWNER. Used as properties on the root window to indicate which selections that are owned by rdesktop. */ static Atom rdesktop_primary_owner_atom, rdesktop_clipboard_owner_atom; static Atom format_string_atom, format_utf8_string_atom, format_unicode_atom; /* Atom of the INCR clipboard type (see ICCCM on "INCR Properties") */ static Atom incr_atom; /* Stores the last "selection request" (= another X client requesting clipboard data from us). To satisfy such a request, we request the clipboard data from the RDP server. When we receive the response from the RDP server (asynchronously), this variable gives us the context to proceed. */ static XSelectionRequestEvent selection_request; /* Denotes we have a pending selection request. */ static RD_BOOL has_selection_request; /* Stores the clipboard format (CF_TEXT, CF_UNICODETEXT etc.) requested in the last CLIPDR_DATA_REQUEST (= the RDP server requesting clipboard data from us). When we receive this data from whatever X client offering it, this variable gives us the context to proceed. */ static int rdp_clipboard_request_format; /* Array of offered clipboard targets that will be sent to fellow X clients upon a TARGETS request. */ static Atom targets[MAX_TARGETS]; static int num_targets; /* Denotes that an rdesktop (not this rdesktop) is owning the selection, allowing us to interchange Windows native clipboard data directly. */ static RD_BOOL rdesktop_is_selection_owner = False; /* Time when we acquired the selection. */ static Time acquire_time = 0; /* Denotes that an INCR ("chunked") transfer is in progress. */ static int g_waiting_for_INCR = 0; /* Denotes the target format of the ongoing INCR ("chunked") transfer. */ static Atom g_incr_target = 0; /* Buffers an INCR transfer. */ static uint8 *g_clip_buffer = 0; /* Denotes the size of g_clip_buffer. */ static uint32 g_clip_buflen = 0; /* Translates CR-LF to LF. Changes the string in-place. Does not stop on embedded nulls. The length is updated. */ static void crlf2lf(uint8 * data, uint32 * length) { uint8 *dst, *src; src = dst = data; while (src < data + *length) { if (*src != '\x0d') *dst++ = *src; src++; } *length = dst - data; } #ifdef USE_UNICODE_CLIPBOARD /* Translate LF to CR-LF. To do this, we must allocate more memory. The returned string is null-terminated, as required by CF_UNICODETEXT. The size is updated. */ static uint8 * utf16_lf2crlf(uint8 * data, uint32 * size) { uint8 *result; uint16 *inptr, *outptr; RD_BOOL swap_endianess; /* Worst case: Every char is LF */ result = xmalloc((*size * 2) + 2); if (result == NULL) return NULL; inptr = (uint16 *) data; outptr = (uint16 *) result; /* Check for a reversed BOM */ swap_endianess = (*inptr == 0xfffe); uint16 uvalue_previous = 0; /* Kept so we'll avoid translating CR-LF to CR-CR-LF */ while ((uint8 *) inptr < data + *size) { uint16 uvalue = *inptr; if (swap_endianess) uvalue = ((uvalue << 8) & 0xff00) + (uvalue >> 8); if ((uvalue == 0x0a) && (uvalue_previous != 0x0d)) *outptr++ = swap_endianess ? 0x0d00 : 0x0d; uvalue_previous = uvalue; *outptr++ = *inptr++; } *outptr++ = 0; /* null termination */ *size = (uint8 *) outptr - result; return result; } #else /* Translate LF to CR-LF. To do this, we must allocate more memory. The length is updated. */ static uint8 * lf2crlf(uint8 * data, uint32 * length) { uint8 *result, *p, *o; /* Worst case: Every char is LF */ result = xmalloc(*length * 2); p = data; o = result; uint8 previous = '\0'; /* Kept to avoid translating CR-LF to CR-CR-LF */ while (p < data + *length) { if ((*p == '\x0a') && (previous != '\x0d')) *o++ = '\x0d'; previous = *p; *o++ = *p++; } *length = o - result; /* Convenience */ *o++ = '\0'; return result; } #endif static void xclip_provide_selection(XSelectionRequestEvent * req, Atom type, unsigned int format, uint8 * data, uint32 length) { XEvent xev; DEBUG_CLIPBOARD(("xclip_provide_selection: requestor=0x%08x, target=%s, property=%s, length=%u\n", (unsigned) req->requestor, XGetAtomName(g_display, req->target), XGetAtomName(g_display, req->property), (unsigned) length)); XChangeProperty(g_display, req->requestor, req->property, type, format, PropModeReplace, data, length); xev.xselection.type = SelectionNotify; xev.xselection.serial = 0; xev.xselection.send_event = True; xev.xselection.requestor = req->requestor; xev.xselection.selection = req->selection; xev.xselection.target = req->target; xev.xselection.property = req->property; xev.xselection.time = req->time; XSendEvent(g_display, req->requestor, False, NoEventMask, &xev); } /* Replies a clipboard requestor, telling that we're unable to satisfy his request for whatever reason. This has the benefit of finalizing the clipboard negotiation and thus not leaving our requestor lingering (and, potentially, stuck). */ static void xclip_refuse_selection(XSelectionRequestEvent * req) { XEvent xev; DEBUG_CLIPBOARD(("xclip_refuse_selection: requestor=0x%08x, target=%s, property=%s\n", (unsigned) req->requestor, XGetAtomName(g_display, req->target), XGetAtomName(g_display, req->property))); xev.xselection.type = SelectionNotify; xev.xselection.serial = 0; xev.xselection.send_event = True; xev.xselection.requestor = req->requestor; xev.xselection.selection = req->selection; xev.xselection.target = req->target; xev.xselection.property = None; xev.xselection.time = req->time; XSendEvent(g_display, req->requestor, False, NoEventMask, &xev); } /* Wrapper for cliprdr_send_data which also cleans the request state. */ static void helper_cliprdr_send_response(uint8 * data, uint32 length) { if (rdp_clipboard_request_format != 0) { cliprdr_send_data(data, length); rdp_clipboard_request_format = 0; if (!rdesktop_is_selection_owner) cliprdr_send_simple_native_format_announce(RDP_CF_TEXT); } } /* Last resort, when we have to provide clipboard data but for whatever reason couldn't get any. */ static void helper_cliprdr_send_empty_response() { helper_cliprdr_send_response(NULL, 0); } /* Replies with clipboard data to RDP, converting it from the target format to the expected RDP format as necessary. Returns true if data was sent. */ static RD_BOOL xclip_send_data_with_convert(uint8 * source, size_t source_size, Atom target) { DEBUG_CLIPBOARD(("xclip_send_data_with_convert: target=%s, size=%u\n", XGetAtomName(g_display, target), (unsigned) source_size)); #ifdef USE_UNICODE_CLIPBOARD if (target == format_string_atom || target == format_unicode_atom || target == format_utf8_string_atom) { size_t unicode_buffer_size; char *unicode_buffer; iconv_t cd; size_t unicode_buffer_size_remaining; char *unicode_buffer_remaining; char *data_remaining; size_t data_size_remaining; uint32 translated_data_size; uint8 *translated_data; if (rdp_clipboard_request_format != RDP_CF_TEXT) return False; /* Make an attempt to convert any string we send to Unicode. We don't know what the RDP server's ANSI Codepage is, or how to convert to it, so using CF_TEXT is not safe (and is unnecessary, since all WinNT versions are Unicode-minded). */ if (target == format_string_atom) { char *locale_charset = nl_langinfo(CODESET); cd = iconv_open(WINDOWS_CODEPAGE, locale_charset); if (cd == (iconv_t) - 1) { DEBUG_CLIPBOARD(("Locale charset %s not found in iconv. Unable to convert clipboard text.\n", locale_charset)); return False; } unicode_buffer_size = source_size * 4; } else if (target == format_unicode_atom) { cd = iconv_open(WINDOWS_CODEPAGE, "UCS-2"); if (cd == (iconv_t) - 1) { return False; } unicode_buffer_size = source_size; } else if (target == format_utf8_string_atom) { cd = iconv_open(WINDOWS_CODEPAGE, "UTF-8"); if (cd == (iconv_t) - 1) { return False; } /* UTF-8 is guaranteed to be less or equally compact as UTF-16 for all Unicode chars >=2 bytes. */ unicode_buffer_size = source_size * 2; } else { return False; } unicode_buffer = xmalloc(unicode_buffer_size); unicode_buffer_size_remaining = unicode_buffer_size; unicode_buffer_remaining = unicode_buffer; data_remaining = (char *) source; data_size_remaining = source_size; iconv(cd, (ICONV_CONST char **) &data_remaining, &data_size_remaining, &unicode_buffer_remaining, &unicode_buffer_size_remaining); iconv_close(cd); /* translate linebreaks */ translated_data_size = unicode_buffer_size - unicode_buffer_size_remaining; translated_data = utf16_lf2crlf((uint8 *) unicode_buffer, &translated_data_size); if (translated_data != NULL) { DEBUG_CLIPBOARD(("Sending Unicode string of %d bytes\n", translated_data_size)); helper_cliprdr_send_response(translated_data, translated_data_size); xfree(translated_data); /* Not the same thing as XFree! */ } xfree(unicode_buffer); return True; } #else if (target == format_string_atom) { uint8 *translated_data; uint32 length = source_size; if (rdp_clipboard_request_format != RDP_CF_TEXT) return False; DEBUG_CLIPBOARD(("Translating linebreaks before sending data\n")); translated_data = lf2crlf(source, &length); if (translated_data != NULL) { helper_cliprdr_send_response(translated_data, length + 1); xfree(translated_data); /* Not the same thing as XFree! */ } return True; } #endif else if (target == rdesktop_native_atom) { helper_cliprdr_send_response(source, source_size + 1); return True; } else { return False; } } static void xclip_clear_target_props() { XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom); XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom); XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom); } static void xclip_notify_change() { XChangeProperty(g_display, DefaultRootWindow(g_display), rdesktop_selection_notify_atom, XA_INTEGER, 32, PropModeReplace, NULL, 0); } static void xclip_probe_selections() { Window primary_owner, clipboard_owner; if (probing_selections) { DEBUG_CLIPBOARD(("Already probing selections. Scheduling reprobe.\n")); reprobe_selections = True; return; } DEBUG_CLIPBOARD(("Probing selections.\n")); probing_selections = True; reprobe_selections = False; xclip_clear_target_props(); if (auto_mode) primary_owner = XGetSelectionOwner(g_display, primary_atom); else primary_owner = None; clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom); /* If we own all relevant selections then don't do anything. */ if (((primary_owner == g_wnd) || !auto_mode) && (clipboard_owner == g_wnd)) goto end; /* Both available */ if ((primary_owner != None) && (clipboard_owner != None)) { primary_timestamp = 0; clipboard_timestamp = 0; XConvertSelection(g_display, primary_atom, timestamp_atom, rdesktop_primary_timestamp_target_atom, g_wnd, CurrentTime); XConvertSelection(g_display, clipboard_atom, timestamp_atom, rdesktop_clipboard_timestamp_target_atom, g_wnd, CurrentTime); return; } /* Just PRIMARY */ if (primary_owner != None) { XConvertSelection(g_display, primary_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } /* Just CLIPBOARD */ if (clipboard_owner != None) { XConvertSelection(g_display, clipboard_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } DEBUG_CLIPBOARD(("No owner of any selection.\n")); /* FIXME: Without XFIXES, we cannot reliably know the formats offered by an upcoming selection owner, so we just lie about him offering RDP_CF_TEXT. */ cliprdr_send_simple_native_format_announce(RDP_CF_TEXT); end: probing_selections = False; } /* This function is called for SelectionNotify events. The SelectionNotify event is sent from the clipboard owner to the requestor after his request was satisfied. If this function is called, we're the requestor side. */ #ifndef MAKE_PROTO void xclip_handle_SelectionNotify(XSelectionEvent * event) { unsigned long nitems, bytes_left; XWindowAttributes wa; Atom type; Atom *supported_targets; int res, i, format; uint8 *data = NULL; if (event->property == None) goto fail; DEBUG_CLIPBOARD(("xclip_handle_SelectionNotify: selection=%s, target=%s, property=%s\n", XGetAtomName(g_display, event->selection), XGetAtomName(g_display, event->target), XGetAtomName(g_display, event->property))); if (event->target == timestamp_atom) { if (event->selection == primary_atom) { res = XGetWindowProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom, 0, XMaxRequestSize(g_display), False, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data); } else { res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom, 0, XMaxRequestSize(g_display), False, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data); } if ((res != Success) || (nitems != 1) || (format != 32)) { DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); goto fail; } if (event->selection == primary_atom) { primary_timestamp = *(Time *) data; if (primary_timestamp == 0) primary_timestamp++; XDeleteProperty(g_display, g_wnd, rdesktop_primary_timestamp_target_atom); DEBUG_CLIPBOARD(("Got PRIMARY timestamp: %u\n", (unsigned) primary_timestamp)); } else { clipboard_timestamp = *(Time *) data; if (clipboard_timestamp == 0) clipboard_timestamp++; XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_timestamp_target_atom); DEBUG_CLIPBOARD(("Got CLIPBOARD timestamp: %u\n", (unsigned) clipboard_timestamp)); } XFree(data); if (primary_timestamp && clipboard_timestamp) { if (primary_timestamp > clipboard_timestamp) { DEBUG_CLIPBOARD(("PRIMARY is most recent selection.\n")); XConvertSelection(g_display, primary_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, event->time); } else { DEBUG_CLIPBOARD(("CLIPBOARD is most recent selection.\n")); XConvertSelection(g_display, clipboard_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, event->time); } } return; } if (probing_selections && reprobe_selections) { probing_selections = False; xclip_probe_selections(); return; } res = XGetWindowProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, 0, XMaxRequestSize(g_display), False, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data); xclip_clear_target_props(); if (res != Success) { DEBUG_CLIPBOARD(("XGetWindowProperty failed!\n")); goto fail; } if (type == incr_atom) { DEBUG_CLIPBOARD(("Received INCR.\n")); XGetWindowAttributes(g_display, g_wnd, &wa); if ((wa.your_event_mask | PropertyChangeMask) != wa.your_event_mask) { XSelectInput(g_display, g_wnd, (wa.your_event_mask | PropertyChangeMask)); } XFree(data); g_incr_target = event->target; g_waiting_for_INCR = 1; goto end; } /* Negotiate target format */ if (event->target == targets_atom) { /* Determine the best of text targets that we have available: Prefer UTF8_STRING > text/unicode (unspecified encoding) > STRING (ignore TEXT and COMPOUND_TEXT because we don't have code to handle them) */ int text_target_satisfaction = 0; Atom best_text_target = 0; /* measures how much we're satisfied with what we found */ if (type != None) { supported_targets = (Atom *) data; for (i = 0; i < nitems; i++) { DEBUG_CLIPBOARD(("Target %d: %s\n", i, XGetAtomName(g_display, supported_targets[i]))); if (supported_targets[i] == format_string_atom) { if (text_target_satisfaction < 1) { DEBUG_CLIPBOARD(("Other party supports STRING, choosing that as best_target\n")); best_text_target = supported_targets[i]; text_target_satisfaction = 1; } } #ifdef USE_UNICODE_CLIPBOARD else if (supported_targets[i] == format_unicode_atom) { if (text_target_satisfaction < 2) { DEBUG_CLIPBOARD(("Other party supports text/unicode, choosing that as best_target\n")); best_text_target = supported_targets[i]; text_target_satisfaction = 2; } } else if (supported_targets[i] == format_utf8_string_atom) { if (text_target_satisfaction < 3) { DEBUG_CLIPBOARD(("Other party supports UTF8_STRING, choosing that as best_target\n")); best_text_target = supported_targets[i]; text_target_satisfaction = 3; } } #endif else if (supported_targets[i] == rdesktop_clipboard_formats_atom) { if (probing_selections && (text_target_satisfaction < 4)) { DEBUG_CLIPBOARD(("Other party supports native formats, choosing that as best_target\n")); best_text_target = supported_targets[i]; text_target_satisfaction = 4; } } } } /* Kickstarting the next step in the process of satisfying RDP's clipboard request -- specifically, requesting the actual clipboard data. */ if ((best_text_target != 0) && (!probing_selections || (best_text_target == rdesktop_clipboard_formats_atom))) { XConvertSelection(g_display, event->selection, best_text_target, rdesktop_clipboard_target_atom, g_wnd, event->time); goto end; } else { DEBUG_CLIPBOARD(("Unable to find a textual target to satisfy RDP clipboard text request\n")); goto fail; } } else { if (probing_selections) { Window primary_owner, clipboard_owner; /* FIXME: Without XFIXES, we must make sure that the other rdesktop owns all relevant selections or we might try to get a native format from non-rdesktop window later on. */ clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom); if (auto_mode) primary_owner = XGetSelectionOwner(g_display, primary_atom); else primary_owner = clipboard_owner; if (primary_owner != clipboard_owner) goto fail; DEBUG_CLIPBOARD(("Got fellow rdesktop formats\n")); probing_selections = False; rdesktop_is_selection_owner = True; cliprdr_send_native_format_announce(data, nitems); } else if ((!nitems) || (!xclip_send_data_with_convert(data, nitems, event->target))) { goto fail; } } end: if (data) XFree(data); return; fail: xclip_clear_target_props(); if (probing_selections) { DEBUG_CLIPBOARD(("Unable to find suitable target. Using default text format.\n")); probing_selections = False; rdesktop_is_selection_owner = False; /* FIXME: Without XFIXES, we cannot reliably know the formats offered by an upcoming selection owner, so we just lie about him offering RDP_CF_TEXT. */ cliprdr_send_simple_native_format_announce(RDP_CF_TEXT); } else { helper_cliprdr_send_empty_response(); } goto end; } /* This function is called for SelectionRequest events. The SelectionRequest event is sent from the requestor to the clipboard owner to request clipboard data. */ void xclip_handle_SelectionRequest(XSelectionRequestEvent * event) { unsigned long nitems, bytes_left; unsigned char *prop_return = NULL; int format, res; Atom type; DEBUG_CLIPBOARD(("xclip_handle_SelectionRequest: selection=%s, target=%s, property=%s\n", XGetAtomName(g_display, event->selection), XGetAtomName(g_display, event->target), XGetAtomName(g_display, event->property))); if (event->target == targets_atom) { xclip_provide_selection(event, XA_ATOM, 32, (uint8 *) & targets, num_targets); return; } else if (event->target == timestamp_atom) { xclip_provide_selection(event, XA_INTEGER, 32, (uint8 *) & acquire_time, 1); return; } else if (event->target == rdesktop_clipboard_formats_atom) { xclip_provide_selection(event, XA_STRING, 8, formats_data, formats_data_length); } else { /* All the following targets require an async operation with the RDP server and currently we don't do X clipboard request queueing so we can only handle one such request at a time. */ if (has_selection_request) { DEBUG_CLIPBOARD(("Error: Another clipboard request was already sent to the RDP server and not yet responded. Refusing this request.\n")); xclip_refuse_selection(event); return; } if (event->target == rdesktop_native_atom) { /* Before the requestor makes a request for the _RDESKTOP_NATIVE target, he should declare requestor[property] = CF_SOMETHING. */ res = XGetWindowProperty(g_display, event->requestor, event->property, 0, 1, True, XA_INTEGER, &type, &format, &nitems, &bytes_left, &prop_return); if (res != Success || (!prop_return)) { DEBUG_CLIPBOARD(("Requested native format but didn't specifiy which.\n")); xclip_refuse_selection(event); return; } format = *(uint32 *) prop_return; XFree(prop_return); } else if (event->target == format_string_atom || event->target == XA_STRING) { /* STRING and XA_STRING are defined to be ISO8859-1 */ format = CF_TEXT; } else if (event->target == format_utf8_string_atom) { #ifdef USE_UNICODE_CLIPBOARD format = CF_UNICODETEXT; #else DEBUG_CLIPBOARD(("Requested target unavailable due to lack of Unicode support. (It was not in TARGETS, so why did you ask for it?!)\n")); xclip_refuse_selection(event); return; #endif } else if (event->target == format_unicode_atom) { /* Assuming text/unicode to be UTF-16 */ format = CF_UNICODETEXT; } else { DEBUG_CLIPBOARD(("Requested target unavailable. (It was not in TARGETS, so why did you ask for it?!)\n")); xclip_refuse_selection(event); return; } cliprdr_send_data_request(format); selection_request = *event; has_selection_request = True; return; /* wait for data */ } } /* While this rdesktop holds ownership over the clipboard, it means the clipboard data is offered by the RDP server (and when it is pasted inside RDP, there's no network roundtrip). This event (SelectionClear) symbolizes this rdesktop lost onwership of the clipboard to some other X client. We should find out what clipboard formats this other client offers and announce that to RDP. */ void xclip_handle_SelectionClear(void) { DEBUG_CLIPBOARD(("xclip_handle_SelectionClear\n")); xclip_notify_change(); xclip_probe_selections(); } /* Called when any property changes in our window or the root window. */ void xclip_handle_PropertyNotify(XPropertyEvent * event) { unsigned long nitems; unsigned long offset = 0; unsigned long bytes_left = 1; int format; XWindowAttributes wa; uint8 *data; Atom type; if (event->state == PropertyNewValue && g_waiting_for_INCR) { DEBUG_CLIPBOARD(("x_clip_handle_PropertyNotify: g_waiting_for_INCR != 0\n")); while (bytes_left > 0) { /* Unlike the specification, we don't set the 'delete' arugment to True since we slurp the INCR's chunks in even-smaller chunks of 4096 bytes. */ if ((XGetWindowProperty (g_display, g_wnd, rdesktop_clipboard_target_atom, offset, 4096L, False, AnyPropertyType, &type, &format, &nitems, &bytes_left, &data) != Success)) { XFree(data); return; } if (nitems == 0) { /* INCR transfer finished */ XGetWindowAttributes(g_display, g_wnd, &wa); XSelectInput(g_display, g_wnd, (wa.your_event_mask ^ PropertyChangeMask)); XFree(data); g_waiting_for_INCR = 0; if (g_clip_buflen > 0) { if (!xclip_send_data_with_convert (g_clip_buffer, g_clip_buflen, g_incr_target)) { helper_cliprdr_send_empty_response(); } xfree(g_clip_buffer); g_clip_buffer = NULL; g_clip_buflen = 0; } } else { /* Another chunk in the INCR transfer */ offset += (nitems / 4); /* offset at which to begin the next slurp */ g_clip_buffer = xrealloc(g_clip_buffer, g_clip_buflen + nitems); memcpy(g_clip_buffer + g_clip_buflen, data, nitems); g_clip_buflen += nitems; XFree(data); } } XDeleteProperty(g_display, g_wnd, rdesktop_clipboard_target_atom); return; } if ((event->atom == rdesktop_selection_notify_atom) && (event->window == DefaultRootWindow(g_display))) xclip_probe_selections(); } #endif /* Called when the RDP server announces new clipboard data formats. In response, we: - take ownership over the clipboard - declare those formats in their Windows native form to other rdesktop instances on this X server */ void ui_clip_format_announce(uint8 * data, uint32 length) { acquire_time = g_last_gesturetime; XSetSelectionOwner(g_display, primary_atom, g_wnd, acquire_time); if (XGetSelectionOwner(g_display, primary_atom) != g_wnd) warning("Failed to aquire ownership of PRIMARY clipboard\n"); XSetSelectionOwner(g_display, clipboard_atom, g_wnd, acquire_time); if (XGetSelectionOwner(g_display, clipboard_atom) != g_wnd) warning("Failed to aquire ownership of CLIPBOARD clipboard\n"); if (formats_data) xfree(formats_data); formats_data = xmalloc(length); memcpy(formats_data, data, length); formats_data_length = length; xclip_notify_change(); } /* Called when the RDP server responds with clipboard data (after we've requested it). */ void ui_clip_handle_data(uint8 * data, uint32 length) { RD_BOOL free_data = False; if (length == 0) { xclip_refuse_selection(&selection_request); has_selection_request = False; return; } if (selection_request.target == format_string_atom || selection_request.target == XA_STRING) { /* We're expecting a CF_TEXT response */ uint8 *firstnull; /* translate linebreaks */ crlf2lf(data, &length); /* Only send data up to null byte, if any */ firstnull = (uint8 *) strchr((char *) data, '\0'); if (firstnull) { length = firstnull - data + 1; } } #ifdef USE_UNICODE_CLIPBOARD else if (selection_request.target == format_utf8_string_atom) { /* We're expecting a CF_UNICODETEXT response */ iconv_t cd = iconv_open("UTF-8", WINDOWS_CODEPAGE); if (cd != (iconv_t) - 1) { size_t utf8_length = length * 2; char *utf8_data = malloc(utf8_length); size_t utf8_length_remaining = utf8_length; char *utf8_data_remaining = utf8_data; char *data_remaining = (char *) data; size_t length_remaining = (size_t) length; if (utf8_data == NULL) { iconv_close(cd); return; } iconv(cd, (ICONV_CONST char **) &data_remaining, &length_remaining, &utf8_data_remaining, &utf8_length_remaining); iconv_close(cd); free_data = True; data = (uint8 *) utf8_data; length = utf8_length - utf8_length_remaining; /* translate linebreaks (works just as well on UTF-8) */ crlf2lf(data, &length); } } else if (selection_request.target == format_unicode_atom) { /* We're expecting a CF_UNICODETEXT response, so what we're receiving matches our requirements and there's no need for further conversions. */ } #endif else if (selection_request.target == rdesktop_native_atom) { /* Pass as-is */ } else { DEBUG_CLIPBOARD(("ui_clip_handle_data: BUG! I don't know how to convert selection target %s!\n", XGetAtomName(g_display, selection_request.target))); xclip_refuse_selection(&selection_request); has_selection_request = False; return; } xclip_provide_selection(&selection_request, selection_request.target, 8, data, length - 1); has_selection_request = False; if (free_data) free(data); } void ui_clip_request_failed() { xclip_refuse_selection(&selection_request); has_selection_request = False; } void ui_clip_request_data(uint32 format) { Window primary_owner, clipboard_owner; DEBUG_CLIPBOARD(("Request from server for format %d\n", format)); rdp_clipboard_request_format = format; if (probing_selections) { DEBUG_CLIPBOARD(("ui_clip_request_data: Selection probe in progress. Cannot handle request.\n")); helper_cliprdr_send_empty_response(); return; } xclip_clear_target_props(); if (rdesktop_is_selection_owner) { XChangeProperty(g_display, g_wnd, rdesktop_clipboard_target_atom, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &format, 1); XConvertSelection(g_display, primary_atom, rdesktop_native_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } if (auto_mode) primary_owner = XGetSelectionOwner(g_display, primary_atom); else primary_owner = None; clipboard_owner = XGetSelectionOwner(g_display, clipboard_atom); /* Both available */ if ((primary_owner != None) && (clipboard_owner != None)) { primary_timestamp = 0; clipboard_timestamp = 0; XConvertSelection(g_display, primary_atom, timestamp_atom, rdesktop_primary_timestamp_target_atom, g_wnd, CurrentTime); XConvertSelection(g_display, clipboard_atom, timestamp_atom, rdesktop_clipboard_timestamp_target_atom, g_wnd, CurrentTime); return; } /* Just PRIMARY */ if (primary_owner != None) { XConvertSelection(g_display, primary_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } /* Just CLIPBOARD */ if (clipboard_owner != None) { XConvertSelection(g_display, clipboard_atom, targets_atom, rdesktop_clipboard_target_atom, g_wnd, CurrentTime); return; } /* No data available */ helper_cliprdr_send_empty_response(); } void ui_clip_sync(void) { xclip_probe_selections(); } void ui_clip_set_mode(const char *optarg) { g_rdpclip = True; if (str_startswith(optarg, "PRIMARYCLIPBOARD")) auto_mode = True; else if (str_startswith(optarg, "CLIPBOARD")) auto_mode = False; else { warning("Invalid clipboard mode '%s'.\n", optarg); g_rdpclip = False; } } void xclip_init(void) { if (!g_rdpclip) return; if (!cliprdr_init()) return; primary_atom = XInternAtom(g_display, "PRIMARY", False); clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False); targets_atom = XInternAtom(g_display, "TARGETS", False); timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False); rdesktop_clipboard_target_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TARGET", False); rdesktop_primary_timestamp_target_atom = XInternAtom(g_display, "_RDESKTOP_PRIMARY_TIMESTAMP_TARGET", False); rdesktop_clipboard_timestamp_target_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_TIMESTAMP_TARGET", False); incr_atom = XInternAtom(g_display, "INCR", False); format_string_atom = XInternAtom(g_display, "STRING", False); format_utf8_string_atom = XInternAtom(g_display, "UTF8_STRING", False); format_unicode_atom = XInternAtom(g_display, "text/unicode", False); /* rdesktop sets _RDESKTOP_SELECTION_NOTIFY on the root window when acquiring the clipboard. Other interested rdesktops can use this to notify their server of the available formats. */ rdesktop_selection_notify_atom = XInternAtom(g_display, "_RDESKTOP_SELECTION_NOTIFY", False); XSelectInput(g_display, DefaultRootWindow(g_display), PropertyChangeMask); probing_selections = False; rdesktop_native_atom = XInternAtom(g_display, "_RDESKTOP_NATIVE", False); rdesktop_clipboard_formats_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_FORMATS", False); rdesktop_primary_owner_atom = XInternAtom(g_display, "_RDESKTOP_PRIMARY_OWNER", False); rdesktop_clipboard_owner_atom = XInternAtom(g_display, "_RDESKTOP_CLIPBOARD_OWNER", False); num_targets = 0; targets[num_targets++] = targets_atom; targets[num_targets++] = timestamp_atom; targets[num_targets++] = rdesktop_native_atom; targets[num_targets++] = rdesktop_clipboard_formats_atom; #ifdef USE_UNICODE_CLIPBOARD targets[num_targets++] = format_utf8_string_atom; #endif targets[num_targets++] = format_unicode_atom; targets[num_targets++] = format_string_atom; targets[num_targets++] = XA_STRING; } void xclip_deinit(void) { if (XGetSelectionOwner(g_display, primary_atom) == g_wnd) XSetSelectionOwner(g_display, primary_atom, None, acquire_time); if (XGetSelectionOwner(g_display, clipboard_atom) == g_wnd) XSetSelectionOwner(g_display, clipboard_atom, None, acquire_time); xclip_notify_change(); } rdesktop-1.8.3/xkeymap.c0000664000770100510440000006364012336635613014140 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. User interface services - X keyboard mapping Copyright (C) Matthew Chapman 1999-2008 Copyright 2003-2008 Peter Astrand for Cendio AB Copyright 2014 Henrik Andersson for Cendio AB 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 3 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, see . */ #ifdef RDP2VNC #include "vnc/x11stubs.h" #else #include #include #endif #include #include #include #include #include #include "rdesktop.h" #include "scancodes.h" #define KEYMAP_SIZE 0x7f+1 #define KEYMAP_MASK 0x7f #define KEYMAP_MAX_LINE_LENGTH 80 extern Display *g_display; extern Window g_wnd; extern char g_keymapname[16]; extern unsigned int g_keylayout; extern int g_keyboard_type; extern int g_keyboard_subtype; extern int g_keyboard_functionkeys; extern int g_win_button_size; extern RD_BOOL g_enable_compose; extern RDP_VERSION g_rdp_version; extern RD_BOOL g_numlock_sync; static RD_BOOL keymap_loaded; static key_translation_entry *keymap[KEYMAP_SIZE]; static KeySym keypress_keysyms[256]; static int min_keycode; static uint16 remote_modifier_state = 0; static uint16 saved_remote_modifier_state = 0; static void update_modifier_state(uint8 scancode, RD_BOOL pressed); /* Free key_translation structure, including linked list */ static void free_key_translation(key_translation * ptr) { key_translation *next; while (ptr) { next = ptr->next; xfree(ptr); ptr = next; } } /* Free the key_translation_entry for a given keysym and remove from the table */ static void delete_key_translation_entry(KeySym keysym) { uint32 hash; key_translation_entry *ptr; key_translation_entry *next; key_translation_entry *prev; key_translation_entry tmp; /* Faking a prev node allows us to keep the algorithm simple */ hash = keysym & KEYMAP_MASK; ptr = keymap[hash]; tmp.next = ptr; prev = &tmp; while (ptr) { next = ptr->next; if (ptr->keysym == keysym) { free_key_translation(ptr->tr); prev->next = next; xfree(ptr); } else { prev = ptr; } ptr = next; } /* Copy pointer back from our fake node */ keymap[hash] = tmp.next; } /* Allocate and return a new entry in the translation table */ static key_translation_entry * new_key_translation_entry(KeySym keysym) { uint32 hash; key_translation_entry *entry; /* Clear out any existing entry */ delete_key_translation_entry(keysym); /* Allocate the new one */ entry = (key_translation_entry *) xmalloc(sizeof(key_translation_entry)); memset(entry, 0, sizeof(key_translation_entry)); entry->keysym = keysym; /* And insert it at head of list */ hash = keysym & KEYMAP_MASK; entry->next = keymap[hash]; keymap[hash] = entry; return entry; } /* Retrieve the key_translation_entry for a given keysym */ static key_translation_entry * get_key_translation_entry(uint32 keysym) { key_translation_entry *ptr; key_translation_entry *next; ptr = keymap[keysym & KEYMAP_MASK]; while (ptr) { next = ptr->next; if (ptr->keysym == keysym) return ptr; ptr = next; } /* Not found */ return NULL; } static void add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname) { KeySym keysym; key_translation_entry *entry; keysym = XStringToKeysym(keyname); if (keysym == NoSymbol) { DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname)); return; } DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, " "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers)); /* Make a new entry in the table */ entry = new_key_translation_entry(keysym); /* And add the new translation to it */ entry->tr = (key_translation *) xmalloc(sizeof(key_translation)); memset(entry->tr, 0, sizeof(key_translation)); entry->tr->scancode = scancode; entry->tr->modifiers = modifiers; return; } static void add_sequence(char *rest, char *mapname) { KeySym keysym; KeySym seq_keysym; key_translation_entry *entry; key_translation *tr, **prev_next; size_t chars; char keyname[KEYMAP_MAX_LINE_LENGTH]; /* Skip over whitespace after the sequence keyword */ chars = strspn(rest, " \t"); rest += chars; /* Fetch the keysym name */ chars = strcspn(rest, " \t\0"); STRNCPY(keyname, rest, chars + 1); rest += chars; keysym = XStringToKeysym(keyname); if (keysym == NoSymbol) { DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname)); return; } DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname)); entry = new_key_translation_entry(keysym); prev_next = &(entry->tr); while (*rest) { /* Skip whitespace */ chars = strspn(rest, " \t"); rest += chars; /* Fetch the keysym name */ chars = strcspn(rest, " \t\0"); STRNCPY(keyname, rest, chars + 1); rest += chars; /* Handle trailing whitespace */ if (*keyname == 0) break; seq_keysym = XStringToKeysym(keyname); if (seq_keysym == NoSymbol) { DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname, mapname)); delete_key_translation_entry(keysym); return; } /* Allocate space for key_translation structure */ tr = (key_translation *) xmalloc(sizeof(key_translation)); memset(tr, 0, sizeof(key_translation)); /* Do this straight away so the key_translation won't get orphaned on error */ if (!entry->tr) entry->tr = tr; *prev_next = tr; prev_next = &tr->next; tr->seq_keysym = seq_keysym; DEBUG_KBD(("0x%x, ", (unsigned int) seq_keysym)); } DEBUG_KBD(("\n")); } RD_BOOL xkeymap_from_locale(const char *locale) { char *str, *ptr; FILE *fp; /* Create a working copy */ str = xstrdup(locale); /* Truncate at dot and at */ ptr = strrchr(str, '.'); if (ptr) *ptr = '\0'; ptr = strrchr(str, '@'); if (ptr) *ptr = '\0'; /* Replace _ with - */ ptr = strrchr(str, '_'); if (ptr) *ptr = '-'; /* Convert to lowercase */ ptr = str; while (*ptr) { *ptr = tolower((int) *ptr); ptr++; } /* Try to open this keymap (da-dk) */ fp = xkeymap_open(str); if (fp == NULL) { /* Truncate at dash */ ptr = strrchr(str, '-'); if (ptr) *ptr = '\0'; /* Try the short name (da) */ fp = xkeymap_open(str); } if (fp) { fclose(fp); STRNCPY(g_keymapname, str, sizeof(g_keymapname)); xfree(str); return True; } xfree(str); return False; } /* Joins two path components. The result should be freed with xfree(). */ static char * pathjoin(const char *a, const char *b) { char *result; result = xmalloc(PATH_MAX * 2 + 1); if (b[0] == '/') { strncpy(result, b, PATH_MAX); } else { strncpy(result, a, PATH_MAX); strcat(result, "/"); strncat(result, b, PATH_MAX); } return result; } /* Try to open a keymap with fopen() */ FILE * xkeymap_open(const char *filename) { char *path1, *path2; char *home; FILE *fp; /* Try ~/.rdesktop/keymaps */ home = getenv("HOME"); if (home) { path1 = pathjoin(home, ".rdesktop/keymaps"); path2 = pathjoin(path1, filename); xfree(path1); fp = fopen(path2, "r"); xfree(path2); if (fp) return fp; } /* Try KEYMAP_PATH */ path1 = pathjoin(KEYMAP_PATH, filename); fp = fopen(path1, "r"); xfree(path1); if (fp) return fp; /* Try current directory, in case we are running from the source tree */ path1 = pathjoin("keymaps", filename); fp = fopen(path1, "r"); xfree(path1); if (fp) return fp; return NULL; } static RD_BOOL xkeymap_read(char *mapname) { FILE *fp; char line[KEYMAP_MAX_LINE_LENGTH]; unsigned int line_num = 0; unsigned int line_length = 0; char *keyname, *p; char *line_rest; uint8 scancode; uint16 modifiers; fp = xkeymap_open(mapname); if (fp == NULL) { error("Failed to open keymap %s\n", mapname); return False; } /* FIXME: More tolerant on white space */ while (fgets(line, sizeof(line), fp) != NULL) { line_num++; /* Replace the \n with \0 */ p = strchr(line, '\n'); if (p != NULL) *p = 0; line_length = strlen(line); /* Completely empty line */ if (strspn(line, " \t\n\r\f\v") == line_length) { continue; } /* Include */ if (str_startswith(line, "include ")) { if (!xkeymap_read(line + sizeof("include ") - 1)) return False; continue; } /* map */ if (str_startswith(line, "map ")) { g_keylayout = strtoul(line + sizeof("map ") - 1, NULL, 16); DEBUG_KBD(("Keylayout 0x%x\n", g_keylayout)); continue; } /* compose */ if (str_startswith(line, "enable_compose")) { DEBUG_KBD(("Enabling compose handling\n")); g_enable_compose = True; continue; } /* sequence */ if (str_startswith(line, "sequence")) { add_sequence(line + sizeof("sequence") - 1, mapname); continue; } /* keyboard_type */ if (str_startswith(line, "keyboard_type ")) { g_keyboard_type = strtol(line + sizeof("keyboard_type ") - 1, NULL, 16); DEBUG_KBD(("keyboard_type 0x%x\n", g_keyboard_type)); continue; } /* keyboard_subtype */ if (str_startswith(line, "keyboard_subtype ")) { g_keyboard_subtype = strtol(line + sizeof("keyboard_subtype ") - 1, NULL, 16); DEBUG_KBD(("keyboard_subtype 0x%x\n", g_keyboard_subtype)); continue; } /* keyboard_functionkeys */ if (str_startswith(line, "keyboard_functionkeys ")) { g_keyboard_functionkeys = strtol(line + sizeof("keyboard_functionkeys ") - 1, NULL, 16); DEBUG_KBD(("keyboard_functionkeys 0x%x\n", g_keyboard_functionkeys)); continue; } /* Comment */ if (line[0] == '#') { continue; } /* Normal line */ keyname = line; p = strchr(line, ' '); if (p == NULL) { error("Bad line %d in keymap %s\n", line_num, mapname); continue; } else { *p = 0; } /* scancode */ p++; scancode = strtol(p, &line_rest, 16); /* flags */ /* FIXME: Should allow case-insensitive flag names. Fix by using lex+yacc... */ modifiers = 0; if (strstr(line_rest, "altgr")) { MASK_ADD_BITS(modifiers, MapAltGrMask); } if (strstr(line_rest, "shift")) { MASK_ADD_BITS(modifiers, MapLeftShiftMask); } if (strstr(line_rest, "numlock")) { MASK_ADD_BITS(modifiers, MapNumLockMask); } if (strstr(line_rest, "localstate")) { MASK_ADD_BITS(modifiers, MapLocalStateMask); } if (strstr(line_rest, "inhibit")) { MASK_ADD_BITS(modifiers, MapInhibitMask); } add_to_keymap(keyname, scancode, modifiers, mapname); if (strstr(line_rest, "addupper")) { /* Automatically add uppercase key, with same modifiers plus shift */ for (p = keyname; *p; p++) *p = toupper((int) *p); MASK_ADD_BITS(modifiers, MapLeftShiftMask); add_to_keymap(keyname, scancode, modifiers, mapname); } } fclose(fp); return True; } /* Before connecting and creating UI */ void xkeymap_init(void) { unsigned int max_keycode; if (strcmp(g_keymapname, "none")) { if (xkeymap_read(g_keymapname)) keymap_loaded = True; } XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode); } static void send_winkey(uint32 ev_time, RD_BOOL pressed, RD_BOOL leftkey) { uint8 winkey; if (leftkey) winkey = SCANCODE_CHAR_LWIN; else winkey = SCANCODE_CHAR_RWIN; if (pressed) { if (g_rdp_version >= RDP_V5) { rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey); } else { /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */ rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL); rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC); } } else { /* key released */ if (g_rdp_version >= RDP_V5) { rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey); } else { rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC); rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL); } } } static void reset_winkey(uint32 ev_time) { if (g_rdp_version >= RDP_V5) { /* For some reason, it seems to suffice to release *either* the left or right winkey. */ rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN); } } void set_keypress_keysym(unsigned int keycode, KeySym keysym) { if (keycode < 8 || keycode > 255) return; keypress_keysyms[keycode] = keysym; } KeySym reset_keypress_keysym(unsigned int keycode, KeySym keysym) { KeySym ks; if (keycode < 8 || keycode > 255) return keysym; ks = keypress_keysyms[keycode]; if (ks != 0) { keypress_keysyms[keycode] = 0; } else { ks = keysym; } return ks; } /* Handle special key combinations */ RD_BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed) { switch (keysym) { case XK_Return: if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)) && (get_key_state(state, XK_Control_L) || get_key_state(state, XK_Control_R))) { /* Ctrl-Alt-Enter: toggle full screen */ if (pressed) xwin_toggle_fullscreen(); return True; } break; case XK_Break: /* Send Break sequence E0 46 E0 C6 */ if (pressed) { rdp_send_scancode(ev_time, RDP_KEYPRESS, (SCANCODE_EXTENDED | 0x46)); rdp_send_scancode(ev_time, RDP_KEYPRESS, (SCANCODE_EXTENDED | 0xc6)); } /* No release sequence */ return True; break; case XK_Pause: /* According to MS Keyboard Scan Code Specification, pressing Pause should result in E1 1D 45 E1 9D C5. I'm not exactly sure of how this is supposed to be sent via RDP. The code below seems to work, but with the side effect that Left Ctrl stays down. Therefore, we release it when Pause is released. */ if (pressed) { rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0); } else { /* Release Left Ctrl */ rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d, 0); } return True; break; case XK_Meta_L: /* Windows keys */ case XK_Super_L: case XK_Hyper_L: send_winkey(ev_time, pressed, True); return True; break; case XK_Meta_R: case XK_Super_R: case XK_Hyper_R: send_winkey(ev_time, pressed, False); return True; break; case XK_space: /* Prevent access to the Windows system menu in single app mode */ if (g_win_button_size && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))) return True; break; case XK_Num_Lock: /* Synchronize on key release */ if (g_numlock_sync && !pressed) rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(read_keyboard_state()), 0); /* Inhibit */ return True; break; case XK_Overlay1_Enable: /* Toggle SeamlessRDP */ if (pressed) ui_seamless_toggle(); break; } return False; } key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state) { key_translation tr = { 0, 0, 0, 0 }; key_translation *ptr; key_translation_entry *entry; entry = get_key_translation_entry(keysym); ptr = entry ? entry->tr : NULL; if (ptr) { tr = *ptr; if (tr.seq_keysym == 0) /* Normal scancode translation */ { if (MASK_HAS_BITS(tr.modifiers, MapInhibitMask)) { DEBUG_KBD(("Inhibiting key\n")); tr.scancode = 0; return tr; } if (MASK_HAS_BITS(tr.modifiers, MapLocalStateMask)) { /* The modifiers to send for this key should be obtained from the local state. Currently, only shift is implemented. */ if (MASK_HAS_BITS(state, ShiftMask)) { tr.modifiers = MapLeftShiftMask; } } /* Windows interprets CapsLock+Ctrl+key differently from Shift+Ctrl+key. Since we are simulating CapsLock with Shifts, things like Ctrl+f with CapsLock on breaks. To solve this, we are releasing Shift if Ctrl is on, but only if Shift isn't physically pressed. */ if (MASK_HAS_BITS(tr.modifiers, MapShiftMask) && MASK_HAS_BITS(remote_modifier_state, MapCtrlMask) && !MASK_HAS_BITS(state, ShiftMask)) { DEBUG_KBD(("Non-physical Shift + Ctrl pressed, releasing Shift\n")); MASK_REMOVE_BITS(tr.modifiers, MapShiftMask); } DEBUG_KBD(("Found scancode translation, scancode=0x%x, modifiers=0x%x\n", tr.scancode, tr.modifiers)); } } else { if (keymap_loaded) warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym)); /* not in keymap, try to interpret the raw scancode */ if (((int) keycode >= min_keycode) && (keycode <= 0x60)) { tr.scancode = keycode - min_keycode; /* The modifiers to send for this key should be obtained from the local state. Currently, only shift is implemented. */ if (MASK_HAS_BITS(state, ShiftMask)) { tr.modifiers = MapLeftShiftMask; } DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode)); } else { DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode)); } } return tr; } static RD_BOOL is_modifier(uint8 scancode) { switch (scancode) { case SCANCODE_CHAR_LSHIFT: case SCANCODE_CHAR_RSHIFT: case SCANCODE_CHAR_LCTRL: case SCANCODE_CHAR_RCTRL: case SCANCODE_CHAR_LALT: case SCANCODE_CHAR_RALT: case SCANCODE_CHAR_LWIN: case SCANCODE_CHAR_RWIN: case SCANCODE_CHAR_NUMLOCK: return True; default: break; } return False; } void xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time, RD_BOOL pressed, uint8 nesting) { key_translation tr, *ptr; tr = xkeymap_translate_key(keysym, keycode, state); if (tr.seq_keysym == 0) { /* Scancode translation */ if (tr.scancode == 0) return; save_remote_modifiers(tr.scancode); ensure_remote_modifiers(ev_time, tr); rdp_send_scancode(ev_time, pressed ? RDP_KEYPRESS : RDP_KEYRELEASE, tr.scancode); restore_remote_modifiers(ev_time, tr.scancode); return; } /* Sequence, only on key down */ if (pressed) { ptr = &tr; do { DEBUG_KBD(("Handling sequence element, keysym=0x%x\n", (unsigned int) ptr->seq_keysym)); if (nesting++ > 32) { error("Sequence nesting too deep\n"); return; } xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, True, nesting); xkeymap_send_keys(ptr->seq_keysym, keycode, state, ev_time, False, nesting); ptr = ptr->next; } while (ptr); } } uint16 xkeymap_translate_button(unsigned int button) { switch (button) { case Button1: /* left */ return MOUSE_FLAG_BUTTON1; case Button2: /* middle */ return MOUSE_FLAG_BUTTON3; case Button3: /* right */ return MOUSE_FLAG_BUTTON2; case Button4: /* wheel up */ return MOUSE_FLAG_BUTTON4; case Button5: /* wheel down */ return MOUSE_FLAG_BUTTON5; } return 0; } char * get_ksname(uint32 keysym) { char *ksname = NULL; if (keysym == NoSymbol) ksname = "NoSymbol"; else if (!(ksname = XKeysymToString(keysym))) ksname = "(no name)"; return ksname; } void save_remote_modifiers(uint8 scancode) { if (is_modifier(scancode)) return; saved_remote_modifier_state = remote_modifier_state; } void restore_remote_modifiers(uint32 ev_time, uint8 scancode) { key_translation dummy = { }; if (is_modifier(scancode)) return; dummy.scancode = 0; dummy.modifiers = saved_remote_modifier_state; ensure_remote_modifiers(ev_time, dummy); } void ensure_remote_modifiers(uint32 ev_time, key_translation tr) { /* If this key is a modifier, do nothing */ if (is_modifier(tr.scancode)) return; if (!g_numlock_sync) { /* NumLock */ if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask) != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask)) { /* The remote modifier state is not correct */ uint16 new_remote_state; if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)) { DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n")); new_remote_state = KBD_FLAG_NUMLOCK; remote_modifier_state = MapNumLockMask; } else { DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n")); new_remote_state = 0; remote_modifier_state = 0; } rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0); } } /* Shift. Left shift and right shift are treated as equal; either is fine. */ if (MASK_HAS_BITS(tr.modifiers, MapShiftMask) != MASK_HAS_BITS(remote_modifier_state, MapShiftMask)) { /* The remote modifier state is not correct */ if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask)) { /* Needs left shift. Send down. */ rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT); } else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask)) { /* Needs right shift. Send down. */ rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT); } else { /* Should not use this modifier. Send up for shift currently pressed. */ if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)) /* Left shift is down */ rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT); else /* Right shift is down */ rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT); } } /* AltGr */ if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask) != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask)) { /* The remote modifier state is not correct */ if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)) { /* Needs this modifier. Send down. */ rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT); } else { /* Should not use this modifier. Send up. */ rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT); } } } unsigned int read_keyboard_state() { #ifdef RDP2VNC return 0; #else unsigned int state; Window wdummy; int dummy; XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state); return state; #endif } uint16 ui_get_numlock_state(unsigned int state) { uint16 numlock_state = 0; if (get_key_state(state, XK_Num_Lock)) numlock_state = KBD_FLAG_NUMLOCK; return numlock_state; } void reset_modifier_keys() { unsigned int state = read_keyboard_state(); /* reset keys */ uint32 ev_time; ev_time = time(NULL); if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask) && !get_key_state(state, XK_Shift_L)) rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT); if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask) && !get_key_state(state, XK_Shift_R)) rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT); if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask) && !get_key_state(state, XK_Control_L)) rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL); if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask) && !get_key_state(state, XK_Control_R)) rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL); if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L)) rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT); if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) && !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch) && !get_key_state(state, XK_ISO_Level3_Shift)) rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT); reset_winkey(ev_time); if (g_numlock_sync) rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0); } static void update_modifier_state(uint8 scancode, RD_BOOL pressed) { #ifdef WITH_DEBUG_KBD uint16 old_modifier_state; old_modifier_state = remote_modifier_state; #endif switch (scancode) { case SCANCODE_CHAR_LSHIFT: MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed); break; case SCANCODE_CHAR_RSHIFT: MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed); break; case SCANCODE_CHAR_LCTRL: MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed); break; case SCANCODE_CHAR_RCTRL: MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed); break; case SCANCODE_CHAR_LALT: MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed); break; case SCANCODE_CHAR_RALT: MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed); break; case SCANCODE_CHAR_LWIN: MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed); break; case SCANCODE_CHAR_RWIN: MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed); break; case SCANCODE_CHAR_NUMLOCK: /* KeyReleases for NumLocks are sent immediately. Toggle the modifier state only on Keypress */ if (pressed && !g_numlock_sync) { RD_BOOL newNumLockState; newNumLockState = (MASK_HAS_BITS (remote_modifier_state, MapNumLockMask) == False); MASK_CHANGE_BIT(remote_modifier_state, MapNumLockMask, newNumLockState); } } #ifdef WITH_DEBUG_KBD if (old_modifier_state != remote_modifier_state) { DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n", old_modifier_state, pressed)); DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state)); } #endif } /* Send keyboard input */ void rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode) { update_modifier_state(scancode, !(flags & RDP_KEYRELEASE)); if (scancode & SCANCODE_EXTENDED) { DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n", scancode & ~SCANCODE_EXTENDED, flags)); rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT, scancode & ~SCANCODE_EXTENDED, 0); } else { DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags)); rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0); } } rdesktop-1.8.3/xwin.c0000664000770100510440000031017312355231574013442 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. User interface services - X Window System Copyright (C) Matthew Chapman 1999-2008 Copyright 2007-2008 Pierre Ossman for Cendio AB Copyright 2002-2011 Peter Astrand for Cendio AB Copyright 2012-2013 Henrik Andersson for Cendio AB 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 3 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, see . */ #include #include #include #include #include #include #include #include #include "rdesktop.h" #include "xproto.h" #ifdef HAVE_XRANDR #include #endif extern int g_sizeopt; extern int g_width; extern int g_height; extern int g_xpos; extern int g_ypos; extern int g_pos; extern RD_BOOL g_sendmotion; extern RD_BOOL g_fullscreen; extern RD_BOOL g_grab_keyboard; extern RD_BOOL g_hide_decorations; extern RD_BOOL g_pending_resize; extern char g_title[]; extern char g_seamless_spawn_cmd[]; /* Color depth of the RDP session. As of RDP 5.1, it may be 8, 15, 16 or 24. */ extern int g_server_depth; extern int g_win_button_size; Display *g_display; Time g_last_gesturetime; static int g_x_socket; static Screen *g_screen; Window g_wnd; /* SeamlessRDP support */ typedef struct _seamless_group { Window wnd; unsigned long id; unsigned int refcnt; } seamless_group; typedef struct _seamless_window { Window wnd; unsigned long id; unsigned long behind; seamless_group *group; int xoffset, yoffset; int width, height; int state; /* normal/minimized/maximized. */ unsigned int desktop; struct timeval *position_timer; RD_BOOL outstanding_position; unsigned int outpos_serial; int outpos_xoffset, outpos_yoffset; int outpos_width, outpos_height; unsigned int icon_size; unsigned int icon_offset; char icon_buffer[32 * 32 * 4]; struct _seamless_window *next; } seamless_window; static seamless_window *g_seamless_windows = NULL; static unsigned long g_seamless_focused = 0; static RD_BOOL g_seamless_started = False; /* Server end is up and running */ static RD_BOOL g_seamless_active = False; /* We are currently in seamless mode */ static RD_BOOL g_seamless_hidden = False; /* Desktop is hidden on server */ static RD_BOOL g_seamless_broken_restack = False; /* WM does not properly restack */ extern RD_BOOL g_seamless_rdp; extern RD_BOOL g_seamless_persistent_mode; extern uint32 g_embed_wnd; RD_BOOL g_enable_compose = False; RD_BOOL g_Unobscured; /* used for screenblt */ static GC g_gc = NULL; static GC g_create_bitmap_gc = NULL; static GC g_create_glyph_gc = NULL; static XRectangle g_clip_rectangle; static Visual *g_visual; /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual). This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined as far as we're concerned. */ static int g_depth; /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window. This may be larger than g_depth, in which case some of the bits would be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */ static int g_bpp; static XIM g_IM; static XIC g_IC; static XModifierKeymap *g_mod_map; /* Maps logical (xmodmap -pp) pointing device buttons (0-based) back to physical (1-based) indices. */ static unsigned char g_pointer_log_to_phys_map[32]; static Cursor g_current_cursor; static RD_HCURSOR g_null_cursor = NULL; static Atom g_protocol_atom, g_kill_atom; extern Atom g_net_wm_state_atom; extern Atom g_net_wm_desktop_atom; static RD_BOOL g_focused; static RD_BOOL g_mouse_in_wnd; /* Indicates that: 1) visual has 15, 16 or 24 depth and the same color channel masks as its RDP equivalent (implies X server is LE), 2) host is LE This will trigger an optimization whose real value is questionable. */ static RD_BOOL g_compatible_arch; /* Indicates whether RDP's bitmaps and our XImages have the same binary format. If so, we can avoid an expensive translation. Note that this can be true when g_compatible_arch is false, e.g.: RDP(LE) <-> host(BE) <-> X-Server(LE) ('host' is the machine running rdesktop; the host simply memcpy's so its endianess doesn't matter) */ static RD_BOOL g_no_translate_image = False; /* endianness */ static RD_BOOL g_host_be; static RD_BOOL g_xserver_be; static int g_red_shift_r, g_blue_shift_r, g_green_shift_r; static int g_red_shift_l, g_blue_shift_l, g_green_shift_l; /* software backing store */ extern RD_BOOL g_ownbackstore; static Pixmap g_backstore = 0; /* Moving in single app mode */ static RD_BOOL g_moving_wnd; static int g_move_x_offset = 0; static int g_move_y_offset = 0; static RD_BOOL g_using_full_workarea = False; #ifdef WITH_RDPSND extern RD_BOOL g_rdpsnd; #endif /* MWM decorations */ #define MWM_HINTS_DECORATIONS (1L << 1) #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 typedef struct { unsigned long flags; unsigned long functions; unsigned long decorations; long inputMode; unsigned long status; } PropMotifWmHints; typedef struct { uint32 red; uint32 green; uint32 blue; } PixelColour; #define ON_ALL_SEAMLESS_WINDOWS(func, args) \ do { \ seamless_window *sw; \ XRectangle rect; \ if (!g_seamless_windows) break; \ for (sw = g_seamless_windows; sw; sw = sw->next) { \ rect.x = g_clip_rectangle.x - sw->xoffset; \ rect.y = g_clip_rectangle.y - sw->yoffset; \ rect.width = g_clip_rectangle.width; \ rect.height = g_clip_rectangle.height; \ XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \ func args; \ } \ XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \ } while (0) static void seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset) { points[0].x -= xoffset; points[0].y -= yoffset; XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious); points[0].x += xoffset; points[0].y += yoffset; } static void seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset) { points[0].x -= xoffset; points[0].y -= yoffset; XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious); points[0].x += xoffset; points[0].y += yoffset; } #define FILL_RECTANGLE(x,y,cx,cy)\ { \ XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \ ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \ if (g_ownbackstore) \ XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \ } #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\ { \ XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \ } #define FILL_POLYGON(p,np)\ { \ XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \ if (g_ownbackstore) \ XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \ ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \ } #define DRAW_ELLIPSE(x,y,cx,cy,m)\ { \ switch (m) \ { \ case 0: /* Outline */ \ XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \ ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \ if (g_ownbackstore) \ XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \ break; \ case 1: /* Filled */ \ XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \ ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \ if (g_ownbackstore) \ XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \ break; \ } \ } /* colour maps */ extern RD_BOOL g_owncolmap; static Colormap g_xcolmap; static uint32 *g_colmap = NULL; #define TRANSLATE(col) ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] ) #define SET_FOREGROUND(col) XSetForeground(g_display, g_gc, TRANSLATE(col)); #define SET_BACKGROUND(col) XSetBackground(g_display, g_gc, TRANSLATE(col)); static int rop2_map[] = { GXclear, /* 0 */ GXnor, /* DPon */ GXandInverted, /* DPna */ GXcopyInverted, /* Pn */ GXandReverse, /* PDna */ GXinvert, /* Dn */ GXxor, /* DPx */ GXnand, /* DPan */ GXand, /* DPa */ GXequiv, /* DPxn */ GXnoop, /* D */ GXorInverted, /* DPno */ GXcopy, /* P */ GXorReverse, /* PDno */ GXor, /* DPo */ GXset /* 1 */ }; #define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); } #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); } static seamless_window * sw_get_window_by_id(unsigned long id) { seamless_window *sw; for (sw = g_seamless_windows; sw; sw = sw->next) { if (sw->id == id) return sw; } return NULL; } static seamless_window * sw_get_window_by_wnd(Window wnd) { seamless_window *sw; for (sw = g_seamless_windows; sw; sw = sw->next) { if (sw->wnd == wnd) return sw; } return NULL; } static void sw_remove_window(seamless_window * win) { seamless_window *sw, **prevnext = &g_seamless_windows; for (sw = g_seamless_windows; sw; sw = sw->next) { if (sw == win) { *prevnext = sw->next; sw->group->refcnt--; if (sw->group->refcnt == 0) { XDestroyWindow(g_display, sw->group->wnd); xfree(sw->group); } xfree(sw->position_timer); xfree(sw); return; } prevnext = &sw->next; } return; } /* Move all windows except wnd to new desktop */ static void sw_all_to_desktop(Window wnd, unsigned int desktop) { seamless_window *sw; for (sw = g_seamless_windows; sw; sw = sw->next) { if (sw->wnd == wnd) continue; if (sw->desktop != desktop) { ewmh_move_to_desktop(sw->wnd, desktop); sw->desktop = desktop; } } } /* Send our position */ static void sw_update_position(seamless_window * sw) { XWindowAttributes wa; int x, y; Window child_return; unsigned int serial; XGetWindowAttributes(g_display, sw->wnd, &wa); XTranslateCoordinates(g_display, sw->wnd, wa.root, -wa.border_width, -wa.border_width, &x, &y, &child_return); serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0); sw->outstanding_position = True; sw->outpos_serial = serial; sw->outpos_xoffset = x; sw->outpos_yoffset = y; sw->outpos_width = wa.width; sw->outpos_height = wa.height; } /* Check if it's time to send our position */ static void sw_check_timers() { seamless_window *sw; struct timeval now; gettimeofday(&now, NULL); for (sw = g_seamless_windows; sw; sw = sw->next) { if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <)) { timerclear(sw->position_timer); sw_update_position(sw); } } } static void sw_restack_window(seamless_window * sw, unsigned long behind) { seamless_window *sw_above; /* Remove window from stack */ for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next) { if (sw_above->behind == sw->id) break; } if (sw_above) sw_above->behind = sw->behind; /* And then add it at the new position */ for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next) { if (sw_above->behind == behind) break; } if (sw_above) sw_above->behind = sw->id; sw->behind = behind; } static void sw_handle_restack(seamless_window * sw) { Status status; Window root, parent, *children; unsigned int nchildren, i; seamless_window *sw_below; status = XQueryTree(g_display, RootWindowOfScreen(g_screen), &root, &parent, &children, &nchildren); if (!status || !nchildren) return; sw_below = NULL; i = 0; while (children[i] != sw->wnd) { i++; if (i >= nchildren) goto end; } for (i++; i < nchildren; i++) { sw_below = sw_get_window_by_wnd(children[i]); if (sw_below) break; } if (!sw_below && !sw->behind) goto end; if (sw_below && (sw_below->id == sw->behind)) goto end; if (sw_below) { seamless_send_zchange(sw->id, sw_below->id, 0); sw_restack_window(sw, sw_below->id); } else { seamless_send_zchange(sw->id, 0, 0); sw_restack_window(sw, 0); } end: XFree(children); } static seamless_group * sw_find_group(unsigned long id, RD_BOOL dont_create) { seamless_window *sw; seamless_group *sg; XSetWindowAttributes attribs; for (sw = g_seamless_windows; sw; sw = sw->next) { if (sw->group->id == id) return sw->group; } if (dont_create) return NULL; sg = xmalloc(sizeof(seamless_group)); sg->wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs); sg->id = id; sg->refcnt = 0; return sg; } static void mwm_hide_decorations(Window wnd) { PropMotifWmHints motif_hints; Atom hintsatom; /* setup the property */ motif_hints.flags = MWM_HINTS_DECORATIONS; motif_hints.decorations = 0; /* get the atom for the property */ hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False); if (!hintsatom) { warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n"); return; } XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace, (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS); } typedef struct _sw_configurenotify_context { Window window; unsigned long serial; } sw_configurenotify_context; /* Predicate procedure for sw_wait_configurenotify */ static Bool sw_configurenotify_p(Display * display, XEvent * xevent, XPointer arg) { sw_configurenotify_context *context = (sw_configurenotify_context *) arg; if (xevent->xany.type == ConfigureNotify && xevent->xconfigure.window == context->window && xevent->xany.serial >= context->serial) return True; return False; } /* Wait for a ConfigureNotify, with a equal or larger serial, on the specified window. The event will be removed from the queue. We could use XMaskEvent(StructureNotifyMask), but we would then risk throwing away crucial events like DestroyNotify. After a ConfigureWindow, according to ICCCM section 4.1.5, we should recieve a ConfigureNotify, either a real or synthetic one. This indicates that the configure has been "completed". However, some WMs such as several versions of Metacity fails to send synthetic events. See bug http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a timeout to avoid a hang. Tk uses the same approach. */ static void sw_wait_configurenotify(Window wnd, unsigned long serial) { XEvent xevent; sw_configurenotify_context context; struct timeval now; struct timeval future; RD_BOOL got = False; context.window = wnd; context.serial = serial; gettimeofday(&future, NULL); future.tv_usec += 500000; do { if (XCheckIfEvent(g_display, &xevent, sw_configurenotify_p, (XPointer) & context)) { got = True; break; } usleep(100000); gettimeofday(&now, NULL); } while (timercmp(&now, &future, <)); if (!got) { warning("Broken Window Manager: Timeout while waiting for ConfigureNotify\n"); } } /* Get the toplevel window, in case of reparenting */ static Window sw_get_toplevel(Window wnd) { Window root, parent; Window *child_list; unsigned int num_children; while (1) { XQueryTree(g_display, wnd, &root, &parent, &child_list, &num_children); if (root == parent) { break; } else if (!parent) { warning("Internal error: sw_get_toplevel called with root window\n"); } wnd = parent; } return wnd; } /* Check if wnd is already behind a window wrt stacking order */ static RD_BOOL sw_window_is_behind(Window wnd, Window behind) { Window dummy1, dummy2; Window *child_list; unsigned int num_children; unsigned int i; RD_BOOL found_behind = False; RD_BOOL found_wnd = False; wnd = sw_get_toplevel(wnd); behind = sw_get_toplevel(behind); XQueryTree(g_display, RootWindowOfScreen(g_screen), &dummy1, &dummy2, &child_list, &num_children); for (i = num_children - 1; i >= 0; i--) { if (child_list[i] == behind) { found_behind = True; } else if (child_list[i] == wnd) { found_wnd = True; break; } } if (child_list) XFree(child_list); if (!found_wnd) { warning("sw_window_is_behind: Unable to find window 0x%lx\n", wnd); if (!found_behind) { warning("sw_window_is_behind: Unable to find behind window 0x%lx\n", behind); } } return found_behind; } /* Test if the window manager correctly handles window restacking. In particular, we are testing if it's possible to place a window between two other windows. Many WMs such as Metacity can only stack windows on the top or bottom. The window creation should mostly match ui_seamless_create_window. */ static void seamless_restack_test() { /* The goal is to have the middle window between top and bottom. The middle window is initially at the top, though. */ Window wnds[3]; /* top, middle and bottom */ int i; XEvent xevent; XWindowChanges values; unsigned long restack_serial; for (i = 0; i < 3; i++) { char name[64]; wnds[i] = XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, 20, 20, 0, 0, 0); snprintf(name, sizeof(name), "SeamlessRDP restack test - window %d", i); XStoreName(g_display, wnds[i], name); ewmh_set_wm_name(wnds[i], name); /* Hide decorations. Often this means that no reparenting will be done, which makes the restack easier. Besides, we want to mimic our other seamless windows as much as possible. We must still handle the case with reparenting, though. */ mwm_hide_decorations(wnds[i]); /* Prevent windows from appearing in task bar */ XSetTransientForHint(g_display, wnds[i], RootWindowOfScreen(g_screen)); ewmh_set_window_popup(wnds[i]); /* We need to catch MapNotify/ConfigureNotify */ XSelectInput(g_display, wnds[i], StructureNotifyMask); } /* Map Windows. Currently, we assume that XMapRaised places the window on the top of the stack. Should be fairly safe; the window is configured before it's mapped. */ XMapRaised(g_display, wnds[2]); /* bottom */ do { XWindowEvent(g_display, wnds[2], StructureNotifyMask, &xevent); } while (xevent.type != MapNotify); XMapRaised(g_display, wnds[0]); /* top */ do { XWindowEvent(g_display, wnds[0], StructureNotifyMask, &xevent); } while (xevent.type != MapNotify); XMapRaised(g_display, wnds[1]); /* middle */ do { XWindowEvent(g_display, wnds[1], StructureNotifyMask, &xevent); } while (xevent.type != MapNotify); /* The stacking order should now be 1 - 0 - 2 */ if (!sw_window_is_behind(wnds[0], wnds[1]) || !sw_window_is_behind(wnds[2], wnds[1])) { /* Ok, technically a WM is allowed to stack windows arbitrarily, but... */ warning("Broken Window Manager: Unable to test window restacking\n"); g_seamless_broken_restack = True; for (i = 0; i < 3; i++) XDestroyWindow(g_display, wnds[i]); return; } /* Restack, using XReconfigureWMWindow, which should correctly handle reparented windows as well as nonreparenting WMs. */ values.stack_mode = Below; values.sibling = wnds[0]; restack_serial = XNextRequest(g_display); XReconfigureWMWindow(g_display, wnds[1], DefaultScreen(g_display), CWStackMode | CWSibling, &values); sw_wait_configurenotify(wnds[1], restack_serial); /* Now verify that middle is behind top but not behind bottom */ if (!sw_window_is_behind(wnds[1], wnds[0])) { warning("Broken Window Manager: doesn't handle restack (restack request was ignored)\n"); g_seamless_broken_restack = True; } else if (sw_window_is_behind(wnds[1], wnds[2])) { warning("Broken Window Manager: doesn't handle restack (window was moved to bottom)\n"); g_seamless_broken_restack = True; } /* Destroy windows */ for (i = 0; i < 3; i++) { XDestroyWindow(g_display, wnds[i]); do { XWindowEvent(g_display, wnds[i], StructureNotifyMask, &xevent); } while (xevent.type != DestroyNotify); } } #define SPLITCOLOUR15(colour, rv) \ { \ rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \ rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \ rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \ } #define SPLITCOLOUR16(colour, rv) \ { \ rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \ rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \ rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \ } \ #define SPLITCOLOUR24(colour, rv) \ { \ rv.blue = (colour & 0xff0000) >> 16; \ rv.green = (colour & 0x00ff00) >> 8; \ rv.red = (colour & 0x0000ff); \ } #define MAKECOLOUR(pc) \ ((pc.red >> g_red_shift_r) << g_red_shift_l) \ | ((pc.green >> g_green_shift_r) << g_green_shift_l) \ | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \ #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); } #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); } #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \ x = (x << 16) | (x >> 16); } /* The following macros output the same octet sequences on both BE and LE hosts: */ #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; } #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; } #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; } #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; } #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; } #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; } static uint32 translate_colour(uint32 colour) { PixelColour pc; switch (g_server_depth) { case 15: SPLITCOLOUR15(colour, pc); break; case 16: SPLITCOLOUR16(colour, pc); break; case 24: case 32: SPLITCOLOUR24(colour, pc); break; default: /* Avoid warning */ pc.red = 0; pc.green = 0; pc.blue = 0; break; } return MAKECOLOUR(pc); } /* indent is confused by UNROLL8 */ /* *INDENT-OFF* */ /* repeat and unroll, similar to bitmap.c */ /* potentialy any of the following translate */ /* functions can use repeat but just doing */ /* the most common ones */ #define UNROLL8(stm) { stm stm stm stm stm stm stm stm } /* 2 byte output repeat */ #define REPEAT2(stm) \ { \ while (out <= end - 8 * 2) \ UNROLL8(stm) \ while (out < end) \ { stm } \ } /* 3 byte output repeat */ #define REPEAT3(stm) \ { \ while (out <= end - 8 * 3) \ UNROLL8(stm) \ while (out < end) \ { stm } \ } /* 4 byte output repeat */ #define REPEAT4(stm) \ { \ while (out <= end - 8 * 4) \ UNROLL8(stm) \ while (out < end) \ { stm } \ } /* *INDENT-ON* */ static void translate8to8(const uint8 * data, uint8 * out, uint8 * end) { while (out < end) *(out++) = (uint8) g_colmap[*(data++)]; } static void translate8to16(const uint8 * data, uint8 * out, uint8 * end) { uint16 value; if (g_compatible_arch) { /* *INDENT-OFF* */ REPEAT2 ( *((uint16 *) out) = g_colmap[*(data++)]; out += 2; ) /* *INDENT-ON* */ } else if (g_xserver_be) { while (out < end) { value = (uint16) g_colmap[*(data++)]; BOUT16(out, value); } } else { while (out < end) { value = (uint16) g_colmap[*(data++)]; LOUT16(out, value); } } } /* little endian - conversion happens when colourmap is built */ static void translate8to24(const uint8 * data, uint8 * out, uint8 * end) { uint32 value; if (g_compatible_arch) { while (out < end) { value = g_colmap[*(data++)]; BOUT24(out, value); } } else { while (out < end) { value = g_colmap[*(data++)]; LOUT24(out, value); } } } static void translate8to32(const uint8 * data, uint8 * out, uint8 * end) { uint32 value; if (g_compatible_arch) { /* *INDENT-OFF* */ REPEAT4 ( *((uint32 *) out) = g_colmap[*(data++)]; out += 4; ) /* *INDENT-ON* */ } else if (g_xserver_be) { while (out < end) { value = g_colmap[*(data++)]; BOUT32(out, value); } } else { while (out < end) { value = g_colmap[*(data++)]; LOUT32(out, value); } } } static void translate15to16(const uint16 * data, uint8 * out, uint8 * end) { uint16 pixel; uint16 value; PixelColour pc; if (g_xserver_be) { while (out < end) { pixel = *(data++); if (g_host_be) { BSWAP16(pixel); } SPLITCOLOUR15(pixel, pc); value = MAKECOLOUR(pc); BOUT16(out, value); } } else { while (out < end) { pixel = *(data++); if (g_host_be) { BSWAP16(pixel); } SPLITCOLOUR15(pixel, pc); value = MAKECOLOUR(pc); LOUT16(out, value); } } } static void translate15to24(const uint16 * data, uint8 * out, uint8 * end) { uint32 value; uint16 pixel; PixelColour pc; if (g_compatible_arch) { /* *INDENT-OFF* */ REPEAT3 ( pixel = *(data++); SPLITCOLOUR15(pixel, pc); *(out++) = pc.blue; *(out++) = pc.green; *(out++) = pc.red; ) /* *INDENT-ON* */ } else if (g_xserver_be) { while (out < end) { pixel = *(data++); if (g_host_be) { BSWAP16(pixel); } SPLITCOLOUR15(pixel, pc); value = MAKECOLOUR(pc); BOUT24(out, value); } } else { while (out < end) { pixel = *(data++); if (g_host_be) { BSWAP16(pixel); } SPLITCOLOUR15(pixel, pc); value = MAKECOLOUR(pc); LOUT24(out, value); } } } static void translate15to32(const uint16 * data, uint8 * out, uint8 * end) { uint16 pixel; uint32 value; PixelColour pc; if (g_compatible_arch) { /* *INDENT-OFF* */ REPEAT4 ( pixel = *(data++); SPLITCOLOUR15(pixel, pc); *(out++) = pc.blue; *(out++) = pc.green; *(out++) = pc.red; *(out++) = 0; ) /* *INDENT-ON* */ } else if (g_xserver_be) { while (out < end) { pixel = *(data++); if (g_host_be) { BSWAP16(pixel); } SPLITCOLOUR15(pixel, pc); value = MAKECOLOUR(pc); BOUT32(out, value); } } else { while (out < end) { pixel = *(data++); if (g_host_be) { BSWAP16(pixel); } SPLITCOLOUR15(pixel, pc); value = MAKECOLOUR(pc); LOUT32(out, value); } } } static void translate16to16(const uint16 * data, uint8 * out, uint8 * end) { uint16 pixel; uint16 value; PixelColour pc; if (g_xserver_be) { if (g_host_be) { while (out < end) { pixel = *(data++); BSWAP16(pixel); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); BOUT16(out, value); } } else { while (out < end) { pixel = *(data++); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); BOUT16(out, value); } } } else { if (g_host_be) { while (out < end) { pixel = *(data++); BSWAP16(pixel); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); LOUT16(out, value); } } else { while (out < end) { pixel = *(data++); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); LOUT16(out, value); } } } } static void translate16to24(const uint16 * data, uint8 * out, uint8 * end) { uint32 value; uint16 pixel; PixelColour pc; if (g_compatible_arch) { /* *INDENT-OFF* */ REPEAT3 ( pixel = *(data++); SPLITCOLOUR16(pixel, pc); *(out++) = pc.blue; *(out++) = pc.green; *(out++) = pc.red; ) /* *INDENT-ON* */ } else if (g_xserver_be) { if (g_host_be) { while (out < end) { pixel = *(data++); BSWAP16(pixel); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); BOUT24(out, value); } } else { while (out < end) { pixel = *(data++); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); BOUT24(out, value); } } } else { if (g_host_be) { while (out < end) { pixel = *(data++); BSWAP16(pixel); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); LOUT24(out, value); } } else { while (out < end) { pixel = *(data++); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); LOUT24(out, value); } } } } static void translate16to32(const uint16 * data, uint8 * out, uint8 * end) { uint16 pixel; uint32 value; PixelColour pc; if (g_compatible_arch) { /* *INDENT-OFF* */ REPEAT4 ( pixel = *(data++); SPLITCOLOUR16(pixel, pc); *(out++) = pc.blue; *(out++) = pc.green; *(out++) = pc.red; *(out++) = 0; ) /* *INDENT-ON* */ } else if (g_xserver_be) { if (g_host_be) { while (out < end) { pixel = *(data++); BSWAP16(pixel); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); BOUT32(out, value); } } else { while (out < end) { pixel = *(data++); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); BOUT32(out, value); } } } else { if (g_host_be) { while (out < end) { pixel = *(data++); BSWAP16(pixel); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); LOUT32(out, value); } } else { while (out < end) { pixel = *(data++); SPLITCOLOUR16(pixel, pc); value = MAKECOLOUR(pc); LOUT32(out, value); } } } } static void translate24to16(const uint8 * data, uint8 * out, uint8 * end) { uint32 pixel = 0; uint16 value; PixelColour pc; while (out < end) { pixel = *(data++) << 16; pixel |= *(data++) << 8; pixel |= *(data++); SPLITCOLOUR24(pixel, pc); value = MAKECOLOUR(pc); if (g_xserver_be) { BOUT16(out, value); } else { LOUT16(out, value); } } } static void translate24to24(const uint8 * data, uint8 * out, uint8 * end) { uint32 pixel; uint32 value; PixelColour pc; if (g_xserver_be) { while (out < end) { pixel = *(data++) << 16; pixel |= *(data++) << 8; pixel |= *(data++); SPLITCOLOUR24(pixel, pc); value = MAKECOLOUR(pc); BOUT24(out, value); } } else { while (out < end) { pixel = *(data++) << 16; pixel |= *(data++) << 8; pixel |= *(data++); SPLITCOLOUR24(pixel, pc); value = MAKECOLOUR(pc); LOUT24(out, value); } } } static void translate24to32(const uint8 * data, uint8 * out, uint8 * end) { uint32 pixel; uint32 value; PixelColour pc; if (g_compatible_arch) { /* *INDENT-OFF* */ #ifdef NEED_ALIGN REPEAT4 ( *(out++) = *(data++); *(out++) = *(data++); *(out++) = *(data++); *(out++) = 0; ) #else REPEAT4 ( /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */ *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16); out += 4; data += 3; ) #endif /* *INDENT-ON* */ } else if (g_xserver_be) { while (out < end) { pixel = *(data++) << 16; pixel |= *(data++) << 8; pixel |= *(data++); SPLITCOLOUR24(pixel, pc); value = MAKECOLOUR(pc); BOUT32(out, value); } } else { while (out < end) { pixel = *(data++) << 16; pixel |= *(data++) << 8; pixel |= *(data++); SPLITCOLOUR24(pixel, pc); value = MAKECOLOUR(pc); LOUT32(out, value); } } } static uint8 * translate_image(int width, int height, uint8 * data) { int size; uint8 *out; uint8 *end; /* If RDP depth and X Visual depths match, and arch(endian) matches, no need to translate: just return data. Note: select_visual should've already ensured g_no_translate is only set for compatible depths, but the RDP depth might've changed during connection negotiations. */ /* todo */ if (g_server_depth == 32 && g_depth == 24) { return data; } if (g_no_translate_image) { if ((g_depth == 15 && g_server_depth == 15) || (g_depth == 16 && g_server_depth == 16) || (g_depth == 24 && g_server_depth == 24)) return data; } size = width * height * (g_bpp / 8); out = (uint8 *) xmalloc(size); end = out + size; switch (g_server_depth) { case 24: switch (g_bpp) { case 32: translate24to32(data, out, end); break; case 24: translate24to24(data, out, end); break; case 16: translate24to16(data, out, end); break; } break; case 16: switch (g_bpp) { case 32: translate16to32((uint16 *) data, out, end); break; case 24: translate16to24((uint16 *) data, out, end); break; case 16: translate16to16((uint16 *) data, out, end); break; } break; case 15: switch (g_bpp) { case 32: translate15to32((uint16 *) data, out, end); break; case 24: translate15to24((uint16 *) data, out, end); break; case 16: translate15to16((uint16 *) data, out, end); break; } break; case 8: switch (g_bpp) { case 8: translate8to8(data, out, end); break; case 16: translate8to16(data, out, end); break; case 24: translate8to24(data, out, end); break; case 32: translate8to32(data, out, end); break; } break; } return out; } static void xwin_refresh_pointer_map(void) { unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)]; int i, pointer_buttons; pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map)); if (pointer_buttons > sizeof(phys_to_log_map)) pointer_buttons = sizeof(phys_to_log_map); /* if multiple physical buttons map to the same logical button, then * use the lower numbered physical one */ for (i = pointer_buttons - 1; i >= 0; i--) { /* a user could specify arbitrary values for the logical button * number, ignore any that are abnormally large */ if (phys_to_log_map[i] > sizeof(g_pointer_log_to_phys_map)) continue; g_pointer_log_to_phys_map[phys_to_log_map[i] - 1] = i + 1; } } RD_BOOL get_key_state(unsigned int state, uint32 keysym) { int modifierpos, key, keysymMask = 0; int offset; KeyCode keycode = XKeysymToKeycode(g_display, keysym); if (keycode == NoSymbol) return False; for (modifierpos = 0; modifierpos < 8; modifierpos++) { offset = g_mod_map->max_keypermod * modifierpos; for (key = 0; key < g_mod_map->max_keypermod; key++) { if (g_mod_map->modifiermap[offset + key] == keycode) keysymMask |= 1 << modifierpos; } } return (state & keysymMask) ? True : False; } static void calculate_shifts(uint32 mask, int *shift_r, int *shift_l) { *shift_l = ffs(mask) - 1; mask >>= *shift_l; *shift_r = 8 - ffs(mask & ~(mask >> 1)); } /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask), calculates the bits-per-pixel of this channel (a.k.a. colour weight). */ static unsigned calculate_mask_weight(uint32 mask) { unsigned weight = 0; do { weight += (mask & 1); } while (mask >>= 1); return weight; } static RD_BOOL select_visual(int screen_num) { XPixmapFormatValues *pfm; int pixmap_formats_count, visuals_count; XVisualInfo *vmatches = NULL; XVisualInfo template; int i; unsigned red_weight, blue_weight, green_weight; red_weight = blue_weight = green_weight = 0; if (g_server_depth == -1) { g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display)); } pfm = XListPixmapFormats(g_display, &pixmap_formats_count); if (pfm == NULL) { error("Unable to get list of pixmap formats from display.\n"); XCloseDisplay(g_display); return False; } /* Search for best TrueColor visual */ template.class = TrueColor; template.screen = screen_num; vmatches = XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template, &visuals_count); g_visual = NULL; g_no_translate_image = False; g_compatible_arch = False; if (vmatches != NULL) { for (i = 0; i < visuals_count; ++i) { XVisualInfo *visual_info = &vmatches[i]; RD_BOOL can_translate_to_bpp = False; int j; /* Try to find a no-translation visual that'll allow us to use RDP bitmaps directly as ZPixmaps. */ if (!g_xserver_be && (((visual_info->depth == 15) && /* R5G5B5 */ (visual_info->red_mask == 0x7c00) && (visual_info->green_mask == 0x3e0) && (visual_info->blue_mask == 0x1f)) || ((visual_info->depth == 16) && /* R5G6B5 */ (visual_info->red_mask == 0xf800) && (visual_info->green_mask == 0x7e0) && (visual_info->blue_mask == 0x1f)) || ((visual_info->depth == 24) && /* R8G8B8 */ (visual_info->red_mask == 0xff0000) && (visual_info->green_mask == 0xff00) && (visual_info->blue_mask == 0xff)))) { g_visual = visual_info->visual; g_depth = visual_info->depth; g_compatible_arch = !g_host_be; g_no_translate_image = (visual_info->depth == g_server_depth); if (g_no_translate_image) /* We found the best visual */ break; } else { g_compatible_arch = False; } if (visual_info->depth > 24) { /* Avoid 32-bit visuals and likes like the plague. They're either untested or proven to work bad (e.g. nvidia's Composite 32-bit visual). Most implementation offer a 24-bit visual anyway. */ continue; } /* Only care for visuals, for whose BPPs (not depths!) we have a translateXtoY function. */ for (j = 0; j < pixmap_formats_count; ++j) { if (pfm[j].depth == visual_info->depth) { if ((pfm[j].bits_per_pixel == 16) || (pfm[j].bits_per_pixel == 24) || (pfm[j].bits_per_pixel == 32)) { can_translate_to_bpp = True; } break; } } /* Prefer formats which have the most colour depth. We're being truly aristocratic here, minding each weight on its own. */ if (can_translate_to_bpp) { unsigned vis_red_weight = calculate_mask_weight(visual_info->red_mask); unsigned vis_green_weight = calculate_mask_weight(visual_info->green_mask); unsigned vis_blue_weight = calculate_mask_weight(visual_info->blue_mask); if ((vis_red_weight >= red_weight) && (vis_green_weight >= green_weight) && (vis_blue_weight >= blue_weight)) { red_weight = vis_red_weight; green_weight = vis_green_weight; blue_weight = vis_blue_weight; g_visual = visual_info->visual; g_depth = visual_info->depth; } } } XFree(vmatches); } if (g_visual != NULL) { g_owncolmap = False; calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l); calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l); calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l); } else { template.class = PseudoColor; template.depth = 8; template.colormap_size = 256; vmatches = XGetVisualInfo(g_display, VisualClassMask | VisualDepthMask | VisualColormapSizeMask, &template, &visuals_count); if (vmatches == NULL) { error("No usable TrueColor or PseudoColor visuals on this display.\n"); XCloseDisplay(g_display); XFree(pfm); return False; } /* we use a colourmap, so the default visual should do */ g_owncolmap = True; g_visual = vmatches[0].visual; g_depth = vmatches[0].depth; } g_bpp = 0; for (i = 0; i < pixmap_formats_count; ++i) { XPixmapFormatValues *pf = &pfm[i]; if (pf->depth == g_depth) { g_bpp = pf->bits_per_pixel; if (g_no_translate_image) { switch (g_server_depth) { case 15: case 16: if (g_bpp != 16) g_no_translate_image = False; break; case 24: /* Yes, this will force image translation on most modern servers which use 32 bits for R8G8B8. */ if (g_bpp != 24) g_no_translate_image = False; break; default: g_no_translate_image = False; break; } } /* Pixmap formats list is a depth-to-bpp mapping -- there's just a single entry for every depth, so we can safely break here */ break; } } XFree(pfm); pfm = NULL; return True; } static XErrorHandler g_old_error_handler; static RD_BOOL g_error_expected = False; /* Check if the X11 window corresponding to a seamless window with specified id exists. */ RD_BOOL sw_window_exists(unsigned long id) { seamless_window *sw; char *name; Status sts = 0; sw = sw_get_window_by_id(id); if (!sw) return False; g_error_expected = True; sts = XFetchName(g_display, sw->wnd, &name); g_error_expected = False; if (sts) { XFree(name); } return sts; } static int error_handler(Display * dpy, XErrorEvent * eev) { if (g_error_expected) return 0; return g_old_error_handler(dpy, eev); } /* Initialize the UI. This is done once per process. */ RD_BOOL ui_init(void) { int screen_num; g_display = XOpenDisplay(NULL); if (g_display == NULL) { error("Failed to open display: %s\n", XDisplayName(NULL)); return False; } { uint16 endianess_test = 1; g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test)); } g_old_error_handler = XSetErrorHandler(error_handler); g_xserver_be = (ImageByteOrder(g_display) == MSBFirst); screen_num = DefaultScreen(g_display); g_x_socket = ConnectionNumber(g_display); g_screen = ScreenOfDisplay(g_display, screen_num); g_depth = DefaultDepthOfScreen(g_screen); if (!select_visual(screen_num)) return False; if (g_no_translate_image) { DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n")); } if (g_server_depth > g_bpp) { warning("Remote desktop colour depth %d higher than display colour depth %d.\n", g_server_depth, g_bpp); } DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n", g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be)); if (!g_owncolmap) { g_xcolmap = XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual, AllocNone); if (g_depth <= 8) warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth); } if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always)) { warning("External BackingStore not available. Using internal.\n"); g_ownbackstore = True; } g_mod_map = XGetModifierMapping(g_display); xwin_refresh_pointer_map(); xkeymap_init(); if (g_enable_compose) g_IM = XOpenIM(g_display, NULL, NULL, NULL); xclip_init(); ewmh_init(); if (g_seamless_rdp) { seamless_init(); } DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth)); return True; } /* Initialize connection specific data, such as session size. */ void ui_init_connection(void) { /* * Determine desktop size */ if (g_fullscreen) { g_width = WidthOfScreen(g_screen); g_height = HeightOfScreen(g_screen); g_using_full_workarea = True; } else if (g_sizeopt < 0) { /* Percent of screen */ if (-g_sizeopt >= 100) g_using_full_workarea = True; g_height = HeightOfScreen(g_screen) * (-g_sizeopt) / 100; g_width = WidthOfScreen(g_screen) * (-g_sizeopt) / 100; } else if (g_sizeopt == 1) { /* Fetch geometry from _NET_WORKAREA */ uint32 x, y, cx, cy; if (get_current_workarea(&x, &y, &cx, &cy) == 0) { g_width = cx; g_height = cy; g_using_full_workarea = True; } else { warning("Failed to get workarea: probably your window manager does not support extended hints\n"); g_width = WidthOfScreen(g_screen); g_height = HeightOfScreen(g_screen); } } /* make sure width is a multiple of 4 */ g_width = (g_width + 3) & ~3; } void ui_deinit(void) { xclip_deinit(); if (g_IM != NULL) XCloseIM(g_IM); if (g_null_cursor != NULL) ui_destroy_cursor(g_null_cursor); XFreeModifiermap(g_mod_map); XFreeGC(g_display, g_gc); XCloseDisplay(g_display); g_display = NULL; } static void get_window_attribs(XSetWindowAttributes * attribs) { attribs->background_pixel = BlackPixelOfScreen(g_screen); attribs->border_pixel = WhitePixelOfScreen(g_screen); attribs->backing_store = g_ownbackstore ? NotUseful : Always; attribs->override_redirect = g_fullscreen; attribs->colormap = g_xcolmap; } static void get_input_mask(long *input_mask) { *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | VisibilityChangeMask | FocusChangeMask | StructureNotifyMask; if (g_sendmotion) *input_mask |= PointerMotionMask; if (g_ownbackstore) *input_mask |= ExposureMask; if (g_fullscreen || g_grab_keyboard) *input_mask |= EnterWindowMask; if (g_grab_keyboard) *input_mask |= LeaveWindowMask; } RD_BOOL ui_create_window(void) { uint8 null_pointer_mask[1] = { 0x80 }; uint8 null_pointer_data[24] = { 0x00 }; XSetWindowAttributes attribs; XClassHint *classhints; XSizeHints *sizehints; int wndwidth, wndheight; long input_mask, ic_input_mask; XEvent xevent; wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width; wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height; /* Handle -x-y portion of geometry string */ if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2))) g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width; if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4))) g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height; get_window_attribs(&attribs); g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth, wndheight, 0, g_depth, InputOutput, g_visual, CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | CWBorderPixel, &attribs); if (g_gc == NULL) { g_gc = XCreateGC(g_display, g_wnd, 0, NULL); ui_reset_clip(); } if (g_create_bitmap_gc == NULL) g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL); if ((g_ownbackstore) && (g_backstore == 0)) { g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); /* clear to prevent rubbish being exposed at startup */ XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen)); XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height); } XStoreName(g_display, g_wnd, g_title); ewmh_set_wm_name(g_wnd, g_title); if (g_hide_decorations) mwm_hide_decorations(g_wnd); classhints = XAllocClassHint(); if (classhints != NULL) { classhints->res_name = classhints->res_class = "rdesktop"; XSetClassHint(g_display, g_wnd, classhints); XFree(classhints); } sizehints = XAllocSizeHints(); if (sizehints) { sizehints->flags = PMinSize | PMaxSize; if (g_pos) sizehints->flags |= PPosition; sizehints->min_width = sizehints->max_width = g_width; sizehints->min_height = sizehints->max_height = g_height; XSetWMNormalHints(g_display, g_wnd, sizehints); XFree(sizehints); } if (g_embed_wnd) { XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0); } get_input_mask(&input_mask); if (g_IM != NULL) { g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL); if ((g_IC != NULL) && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL)) input_mask |= ic_input_mask; } XSelectInput(g_display, g_wnd, input_mask); #ifdef HAVE_XRANDR XSelectInput(g_display, RootWindowOfScreen(g_screen), StructureNotifyMask); #endif XMapWindow(g_display, g_wnd); /* wait for VisibilityNotify */ do { XMaskEvent(g_display, VisibilityChangeMask, &xevent); } while (xevent.type != VisibilityNotify); g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured; g_focused = False; g_mouse_in_wnd = False; /* handle the WM_DELETE_WINDOW protocol */ g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True); g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True); XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1); /* create invisible 1x1 cursor to be used as null cursor */ if (g_null_cursor == NULL) g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data, 24); if (g_seamless_rdp) { seamless_reset_state(); seamless_restack_test(); } return True; } void ui_resize_window() { XSizeHints *sizehints; Pixmap bs; sizehints = XAllocSizeHints(); if (sizehints) { sizehints->flags = PMinSize | PMaxSize; sizehints->min_width = sizehints->max_width = g_width; sizehints->min_height = sizehints->max_height = g_height; XSetWMNormalHints(g_display, g_wnd, sizehints); XFree(sizehints); } if (!(g_fullscreen || g_embed_wnd)) { XResizeWindow(g_display, g_wnd, g_width, g_height); } /* create new backstore pixmap */ if (g_backstore != 0) { bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen)); XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height); XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0); XFreePixmap(g_display, g_backstore); g_backstore = bs; } } RD_BOOL ui_have_window() { return g_wnd ? True : False; } void ui_destroy_window(void) { if (g_IC != NULL) XDestroyIC(g_IC); XDestroyWindow(g_display, g_wnd); g_wnd = 0; if (g_backstore) { XFreePixmap(g_display, g_backstore); g_backstore = 0; } } void xwin_toggle_fullscreen(void) { Pixmap contents = 0; if (g_seamless_active) /* Turn off SeamlessRDP mode */ ui_seamless_toggle(); if (!g_ownbackstore) { /* need to save contents of window */ contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth); XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0); } ui_destroy_window(); g_fullscreen = !g_fullscreen; ui_create_window(); XDefineCursor(g_display, g_wnd, g_current_cursor); if (!g_ownbackstore) { XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0); XFreePixmap(g_display, contents); } } static void handle_button_event(XEvent xevent, RD_BOOL down) { uint16 button, flags = 0; g_last_gesturetime = xevent.xbutton.time; /* Reverse the pointer button mapping, e.g. in the case of "left-handed mouse mode"; the RDP session expects to receive physical buttons (true in mstsc as well) and logical button behavior depends on the remote desktop's own mouse settings */ xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1]; button = xkeymap_translate_button(xevent.xbutton.button); if (button == 0) return; if (down) flags = MOUSE_FLAG_DOWN; /* Stop moving window when button is released, regardless of cursor position */ if (g_moving_wnd && (xevent.type == ButtonRelease)) g_moving_wnd = False; /* If win_button_size is nonzero, enable single app mode */ if (xevent.xbutton.y < g_win_button_size) { /* Check from right to left: */ if (xevent.xbutton.x >= g_width - g_win_button_size) { /* The close button, continue */ ; } else if (xevent.xbutton.x >= g_width - g_win_button_size * 2) { /* The maximize/restore button. Do not send to server. It might be a good idea to change the cursor or give some other visible indication that rdesktop inhibited this click */ if (xevent.type == ButtonPress) return; } else if (xevent.xbutton.x >= g_width - g_win_button_size * 3) { /* The minimize button. Iconify window. */ if (xevent.type == ButtonRelease) { /* Release the mouse button outside the minimize button, to prevent the actual minimazation to happen */ rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1); XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display)); return; } } else if (xevent.xbutton.x <= g_win_button_size) { /* The system menu. Ignore. */ if (xevent.type == ButtonPress) return; } else { /* The title bar. */ if (xevent.type == ButtonPress) { if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea) { g_moving_wnd = True; g_move_x_offset = xevent.xbutton.x; g_move_y_offset = xevent.xbutton.y; } return; } } } /* Ignore mouse scroll button release event which will be handled as an additional * scrolldown event on the Windows side. */ if (!down && (button == MOUSE_FLAG_BUTTON4 || button == MOUSE_FLAG_BUTTON5)) { return; } if (xevent.xmotion.window == g_wnd) { rdp_send_input(time(NULL), RDP_INPUT_MOUSE, flags | button, xevent.xbutton.x, xevent.xbutton.y); } else { /* SeamlessRDP */ rdp_send_input(time(NULL), RDP_INPUT_MOUSE, flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root); } } /* Process events in Xlib queue Returns 0 after user quit, 1 otherwise */ static int xwin_process_events(void) { XEvent xevent; KeySym keysym; uint32 ev_time; char str[256]; Status status; int events = 0; seamless_window *sw; while ((XPending(g_display) > 0) && events++ < 20) { XNextEvent(g_display, &xevent); if (!g_wnd) /* Ignore events between ui_destroy_window and ui_create_window */ continue; /* Also ignore root window events except ConfigureNotify */ if (xevent.type != ConfigureNotify && xevent.xany.window == DefaultRootWindow(g_display)) continue; if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True)) { DEBUG_KBD(("Filtering event\n")); continue; } switch (xevent.type) { case VisibilityNotify: if (xevent.xvisibility.window == g_wnd) g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured; break; case ClientMessage: /* the window manager told us to quit */ if ((xevent.xclient.message_type == g_protocol_atom) && ((Atom) xevent.xclient.data.l[0] == g_kill_atom)) { /* When killing a seamless window, close the window on the serverside instead of terminating rdesktop */ sw = sw_get_window_by_wnd(xevent.xclient.window); if (!sw) /* Otherwise, quit */ return 0; /* send seamless destroy process message */ seamless_send_destroy(sw->id); } break; case KeyPress: g_last_gesturetime = xevent.xkey.time; if (g_IC != NULL) /* Multi_key compatible version */ { XmbLookupString(g_IC, &xevent.xkey, str, sizeof(str), &keysym, &status); if (!((status == XLookupKeySym) || (status == XLookupBoth))) { error("XmbLookupString failed with status 0x%x\n", status); break; } } else { /* Plain old XLookupString */ DEBUG_KBD(("\nNo input context, using XLookupString\n")); XLookupString((XKeyEvent *) & xevent, str, sizeof(str), &keysym, NULL); } DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym, get_ksname(keysym))); set_keypress_keysym(xevent.xkey.keycode, keysym); ev_time = time(NULL); if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True)) break; xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state, ev_time, True, 0); break; case KeyRelease: g_last_gesturetime = xevent.xkey.time; XLookupString((XKeyEvent *) & xevent, str, sizeof(str), &keysym, NULL); DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym, get_ksname(keysym))); keysym = reset_keypress_keysym(xevent.xkey.keycode, keysym); ev_time = time(NULL); if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False)) break; xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state, ev_time, False, 0); break; case ButtonPress: handle_button_event(xevent, True); break; case ButtonRelease: handle_button_event(xevent, False); break; case MotionNotify: if (g_moving_wnd) { XMoveWindow(g_display, g_wnd, xevent.xmotion.x_root - g_move_x_offset, xevent.xmotion.y_root - g_move_y_offset); break; } if (g_fullscreen && !g_focused) XSetInputFocus(g_display, g_wnd, RevertToPointerRoot, CurrentTime); if (xevent.xmotion.window == g_wnd) { rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y); } else { /* SeamlessRDP */ rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, xevent.xmotion.x_root, xevent.xmotion.y_root); } break; case FocusIn: if (xevent.xfocus.mode == NotifyGrab) break; g_focused = True; reset_modifier_keys(); if (g_grab_keyboard && g_mouse_in_wnd) XGrabKeyboard(g_display, g_wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); sw = sw_get_window_by_wnd(xevent.xfocus.window); if (!sw) break; /* Menu windows are real X11 windows, with focus. When such a window is destroyed, focus is reverted to the main application window, which would cause us to send FOCUS. This breaks window switching in, say, Seamonkey. We shouldn't need to send FOCUS: Windows should also revert focus to some other window when the menu window is destroyed. So, we only send FOCUS if the previous focus window still exists. */ if (sw->id != g_seamless_focused) { if (sw_window_exists(g_seamless_focused)) seamless_send_focus(sw->id, 0); g_seamless_focused = sw->id; } break; case FocusOut: if (xevent.xfocus.mode == NotifyUngrab) break; g_focused = False; if (xevent.xfocus.mode == NotifyWhileGrabbed) XUngrabKeyboard(g_display, CurrentTime); break; case EnterNotify: /* we only register for this event when in fullscreen mode */ /* or grab_keyboard */ g_mouse_in_wnd = True; if (g_fullscreen) { XSetInputFocus(g_display, g_wnd, RevertToPointerRoot, CurrentTime); break; } if (g_focused) XGrabKeyboard(g_display, g_wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); break; case LeaveNotify: /* we only register for this event when grab_keyboard */ g_mouse_in_wnd = False; XUngrabKeyboard(g_display, CurrentTime); break; case Expose: if (xevent.xexpose.window == g_wnd) { XCopyArea(g_display, g_backstore, xevent.xexpose.window, g_gc, xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height, xevent.xexpose.x, xevent.xexpose.y); } else { sw = sw_get_window_by_wnd(xevent.xexpose.window); if (!sw) break; XCopyArea(g_display, g_backstore, xevent.xexpose.window, g_gc, xevent.xexpose.x + sw->xoffset, xevent.xexpose.y + sw->yoffset, xevent.xexpose.width, xevent.xexpose.height, xevent.xexpose.x, xevent.xexpose.y); } break; case MappingNotify: /* Refresh keyboard mapping if it has changed. This is important for Xvnc, since it allocates keycodes dynamically */ if (xevent.xmapping.request == MappingKeyboard || xevent.xmapping.request == MappingModifier) XRefreshKeyboardMapping(&xevent.xmapping); if (xevent.xmapping.request == MappingModifier) { XFreeModifiermap(g_mod_map); g_mod_map = XGetModifierMapping(g_display); } if (xevent.xmapping.request == MappingPointer) { xwin_refresh_pointer_map(); } break; /* clipboard stuff */ case SelectionNotify: xclip_handle_SelectionNotify(&xevent.xselection); break; case SelectionRequest: xclip_handle_SelectionRequest(&xevent.xselectionrequest); break; case SelectionClear: xclip_handle_SelectionClear(); break; case PropertyNotify: xclip_handle_PropertyNotify(&xevent.xproperty); if (xevent.xproperty.window == g_wnd) break; if (xevent.xproperty.window == DefaultRootWindow(g_display)) break; /* seamless */ sw = sw_get_window_by_wnd(xevent.xproperty.window); if (!sw) break; if ((xevent.xproperty.atom == g_net_wm_state_atom) && (xevent.xproperty.state == PropertyNewValue)) { sw->state = ewmh_get_window_state(sw->wnd); seamless_send_state(sw->id, sw->state, 0); } if ((xevent.xproperty.atom == g_net_wm_desktop_atom) && (xevent.xproperty.state == PropertyNewValue)) { sw->desktop = ewmh_get_window_desktop(sw->wnd); sw_all_to_desktop(sw->wnd, sw->desktop); } break; case MapNotify: if (!g_seamless_active) rdp_send_client_window_status(1); break; case UnmapNotify: if (!g_seamless_active) rdp_send_client_window_status(0); break; case ConfigureNotify: #ifdef HAVE_XRANDR if ((g_sizeopt || g_fullscreen) && xevent.xconfigure.window == DefaultRootWindow(g_display)) { if (xevent.xconfigure.width != WidthOfScreen(g_screen) || xevent.xconfigure.height != HeightOfScreen(g_screen)) { XRRUpdateConfiguration(&xevent); XSync(g_display, False); g_pending_resize = True; } } #endif if (!g_seamless_active) break; sw = sw_get_window_by_wnd(xevent.xconfigure.window); if (!sw) break; gettimeofday(sw->position_timer, NULL); if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >= 1000000) { sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER - 1000000; sw->position_timer->tv_sec += 1; } else { sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER; } sw_handle_restack(sw); break; } } /* Keep going */ return 1; } /* Returns 0 after user quit, 1 otherwise */ int ui_select(int rdp_socket) { int n; fd_set rfds, wfds; struct timeval tv; RD_BOOL s_timeout = False; while (True) { n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket; /* Process any events already waiting */ if (!xwin_process_events()) /* User quit */ return 0; if (g_seamless_active) sw_check_timers(); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(rdp_socket, &rfds); FD_SET(g_x_socket, &rfds); /* default timeout */ tv.tv_sec = 60; tv.tv_usec = 0; #ifdef WITH_RDPSND rdpsnd_add_fds(&n, &rfds, &wfds, &tv); #endif /* add redirection handles */ rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout); seamless_select_timeout(&tv); /* add ctrl slaves handles */ ctrl_add_fds(&n, &rfds); n++; switch (select(n, &rfds, &wfds, NULL, &tv)) { case -1: error("select: %s\n", strerror(errno)); case 0: #ifdef WITH_RDPSND rdpsnd_check_fds(&rfds, &wfds); #endif /* Abort serial read calls */ if (s_timeout) rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True); continue; } #ifdef WITH_RDPSND rdpsnd_check_fds(&rfds, &wfds); #endif rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False); ctrl_check_fds(&rfds, &wfds); if (FD_ISSET(rdp_socket, &rfds)) return 1; } } void ui_move_pointer(int x, int y) { XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y); } RD_HBITMAP ui_create_bitmap(int width, int height, uint8 * data) { XImage *image; Pixmap bitmap; uint8 *tdata; int bitmap_pad; if (g_server_depth == 8) { bitmap_pad = 8; } else { bitmap_pad = g_bpp; if (g_bpp == 24) bitmap_pad = 32; } tdata = (g_owncolmap ? data : translate_image(width, height, data)); bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth); image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0, (char *) tdata, width, height, bitmap_pad, 0); XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height); XFree(image); if (tdata != data) xfree(tdata); return (RD_HBITMAP) bitmap; } void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data) { XImage *image; uint8 *tdata; int bitmap_pad; if (g_server_depth == 8) { bitmap_pad = 8; } else { bitmap_pad = g_bpp; if (g_bpp == 24) bitmap_pad = 32; } tdata = (g_owncolmap ? data : translate_image(width, height, data)); image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0, (char *) tdata, width, height, bitmap_pad, 0); if (g_ownbackstore) { XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy); XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); } else { XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy); ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); } XFree(image); if (tdata != data) xfree(tdata); } void ui_destroy_bitmap(RD_HBITMAP bmp) { XFreePixmap(g_display, (Pixmap) bmp); } RD_HGLYPH ui_create_glyph(int width, int height, uint8 * data) { XImage *image; Pixmap bitmap; int scanline; scanline = (width + 7) / 8; bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1); if (g_create_glyph_gc == 0) g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL); image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data, width, height, 8, scanline); image->byte_order = MSBFirst; image->bitmap_bit_order = MSBFirst; XInitImage(image); XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height); XFree(image); return (RD_HGLYPH) bitmap; } void ui_destroy_glyph(RD_HGLYPH glyph) { XFreePixmap(g_display, (Pixmap) glyph); } /* convert next pixel to 32 bpp */ static int get_next_xor_pixel(uint8 * xormask, int bpp, int *k) { int rv = 0; PixelColour pc; uint8 *s8; uint16 *s16; switch (bpp) { case 1: s8 = xormask + (*k) / 8; rv = (*s8) & (0x80 >> ((*k) % 8)); rv = rv ? 0xffffff : 0; (*k) += 1; break; case 8: s8 = xormask + *k; /* should use colour map */ rv = s8[0]; rv = rv ? 0xffffff : 0; (*k) += 1; break; case 15: s16 = (uint16 *) xormask; SPLITCOLOUR15(s16[*k], pc); rv = (pc.red << 16) | (pc.green << 8) | pc.blue; (*k) += 1; break; case 16: s16 = (uint16 *) xormask; SPLITCOLOUR16(s16[*k], pc); rv = (pc.red << 16) | (pc.green << 8) | pc.blue; (*k) += 1; break; case 24: s8 = xormask + *k; rv = (s8[0] << 16) | (s8[1] << 8) | s8[2]; (*k) += 3; break; case 32: s8 = xormask + *k; rv = (s8[1] << 16) | (s8[2] << 8) | s8[3]; (*k) += 4; break; default: error("unknown bpp in get_next_xor_pixel %d\n", bpp); break; } return rv; } RD_HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * andmask, uint8 * xormask, int bpp) { RD_HGLYPH maskglyph, cursorglyph; XColor bg, fg; Cursor xcursor; uint8 *cursor, *pcursor; uint8 *mask, *pmask; uint8 nextbit; int scanline, offset, delta; int i, j, k; k = 0; scanline = (width + 7) / 8; offset = scanline * height; cursor = (uint8 *) xmalloc(offset); memset(cursor, 0, offset); mask = (uint8 *) xmalloc(offset); memset(mask, 0, offset); if (bpp == 1) { offset = 0; delta = scanline; } else { offset = scanline * height - scanline; delta = -scanline; } /* approximate AND and XOR masks with a monochrome X pointer */ for (i = 0; i < height; i++) { pcursor = &cursor[offset]; pmask = &mask[offset]; for (j = 0; j < scanline; j++) { for (nextbit = 0x80; nextbit != 0; nextbit >>= 1) { if (get_next_xor_pixel(xormask, bpp, &k)) { *pcursor |= (~(*andmask) & nextbit); *pmask |= nextbit; } else { *pcursor |= ((*andmask) & nextbit); *pmask |= (~(*andmask) & nextbit); } } andmask++; pcursor++; pmask++; } offset += delta; } fg.red = fg.blue = fg.green = 0xffff; bg.red = bg.blue = bg.green = 0x0000; fg.flags = bg.flags = DoRed | DoBlue | DoGreen; cursorglyph = ui_create_glyph(width, height, cursor); maskglyph = ui_create_glyph(width, height, mask); xcursor = XCreatePixmapCursor(g_display, (Pixmap) cursorglyph, (Pixmap) maskglyph, &fg, &bg, x, y); ui_destroy_glyph(maskglyph); ui_destroy_glyph(cursorglyph); xfree(mask); xfree(cursor); return (RD_HCURSOR) xcursor; } void ui_set_cursor(RD_HCURSOR cursor) { g_current_cursor = (Cursor) cursor; XDefineCursor(g_display, g_wnd, g_current_cursor); ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor)); } void ui_destroy_cursor(RD_HCURSOR cursor) { XFreeCursor(g_display, (Cursor) cursor); } void ui_set_null_cursor(void) { ui_set_cursor(g_null_cursor); } #define MAKE_XCOLOR(xc,c) \ (xc)->red = ((c)->red << 8) | (c)->red; \ (xc)->green = ((c)->green << 8) | (c)->green; \ (xc)->blue = ((c)->blue << 8) | (c)->blue; \ (xc)->flags = DoRed | DoGreen | DoBlue; RD_HCOLOURMAP ui_create_colourmap(COLOURMAP * colours) { COLOURENTRY *entry; int i, ncolours = colours->ncolours; if (!g_owncolmap) { uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours); XColor xentry; XColor xc_cache[256]; uint32 colour; int colLookup = 256; for (i = 0; i < ncolours; i++) { entry = &colours->colours[i]; MAKE_XCOLOR(&xentry, entry); if (XAllocColor(g_display, g_xcolmap, &xentry) == 0) { /* Allocation failed, find closest match. */ int j = 256; int nMinDist = 3 * 256 * 256; long nDist = nMinDist; /* only get the colors once */ while (colLookup--) { xc_cache[colLookup].pixel = colLookup; xc_cache[colLookup].red = xc_cache[colLookup].green = xc_cache[colLookup].blue = 0; xc_cache[colLookup].flags = 0; XQueryColor(g_display, DefaultColormap(g_display, DefaultScreen(g_display)), &xc_cache[colLookup]); } colLookup = 0; /* approximate the pixel */ while (j--) { if (xc_cache[j].flags) { nDist = ((long) (xc_cache[j].red >> 8) - (long) (xentry.red >> 8)) * ((long) (xc_cache[j].red >> 8) - (long) (xentry.red >> 8)) + ((long) (xc_cache[j].green >> 8) - (long) (xentry.green >> 8)) * ((long) (xc_cache[j].green >> 8) - (long) (xentry.green >> 8)) + ((long) (xc_cache[j].blue >> 8) - (long) (xentry.blue >> 8)) * ((long) (xc_cache[j].blue >> 8) - (long) (xentry.blue >> 8)); } if (nDist < nMinDist) { nMinDist = nDist; xentry.pixel = j; } } } colour = xentry.pixel; /* update our cache */ if (xentry.pixel < 256) { xc_cache[xentry.pixel].red = xentry.red; xc_cache[xentry.pixel].green = xentry.green; xc_cache[xentry.pixel].blue = xentry.blue; } map[i] = colour; } return map; } else { XColor *xcolours, *xentry; Colormap map; xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours); for (i = 0; i < ncolours; i++) { entry = &colours->colours[i]; xentry = &xcolours[i]; xentry->pixel = i; MAKE_XCOLOR(xentry, entry); } map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll); XStoreColors(g_display, map, xcolours, ncolours); xfree(xcolours); return (RD_HCOLOURMAP) map; } } void ui_destroy_colourmap(RD_HCOLOURMAP map) { if (!g_owncolmap) xfree(map); else XFreeColormap(g_display, (Colormap) map); } void ui_set_colourmap(RD_HCOLOURMAP map) { if (!g_owncolmap) { if (g_colmap) xfree(g_colmap); g_colmap = (uint32 *) map; } else { XSetWindowColormap(g_display, g_wnd, (Colormap) map); ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map)); } } void ui_set_clip(int x, int y, int cx, int cy) { g_clip_rectangle.x = x; g_clip_rectangle.y = y; g_clip_rectangle.width = cx; g_clip_rectangle.height = cy; XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); } void ui_reset_clip(void) { g_clip_rectangle.x = 0; g_clip_rectangle.y = 0; g_clip_rectangle.width = g_width; g_clip_rectangle.height = g_height; XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); } void ui_bell(void) { XBell(g_display, 0); } void ui_destblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy) { SET_FUNCTION(opcode); FILL_RECTANGLE(x, y, cx, cy); RESET_FUNCTION(opcode); } static uint8 hatch_patterns[] = { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */ 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */ 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */ }; void ui_patblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* brush */ BRUSH * brush, int bgcolour, int fgcolour) { Pixmap fill; uint8 i, ipattern[8]; SET_FUNCTION(opcode); switch (brush->style) { case 0: /* Solid */ SET_FOREGROUND(fgcolour); FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); break; case 2: /* Hatch */ fill = (Pixmap) ui_create_glyph(8, 8, hatch_patterns + brush->pattern[0] * 8); SET_FOREGROUND(fgcolour); SET_BACKGROUND(bgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); break; case 3: /* Pattern */ if (brush->bd == 0) /* rdp4 brush */ { for (i = 0; i != 8; i++) ipattern[7 - i] = brush->pattern[i]; fill = (Pixmap) ui_create_glyph(8, 8, ipattern); SET_FOREGROUND(bgcolour); SET_BACKGROUND(fgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); } else if (brush->bd->colour_code > 1) /* > 1 bpp */ { fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data); XSetFillStyle(g_display, g_gc, FillTiled); XSetTile(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_bitmap((RD_HBITMAP) fill); } else { fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data); SET_FOREGROUND(bgcolour); SET_BACKGROUND(fgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); } break; default: unimpl("brush %d\n", brush->style); } RESET_FUNCTION(opcode); if (g_ownbackstore) XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); } void ui_screenblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* src */ int srcx, int srcy) { SET_FUNCTION(opcode); if (g_ownbackstore) { XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y); XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y); } else { XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y); } ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); RESET_FUNCTION(opcode); } void ui_memblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* src */ RD_HBITMAP src, int srcx, int srcy) { SET_FUNCTION(opcode); XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y); ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, (Pixmap) src, sw->wnd, g_gc, srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset)); if (g_ownbackstore) XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y); RESET_FUNCTION(opcode); } void ui_triblt(uint8 opcode, /* dest */ int x, int y, int cx, int cy, /* src */ RD_HBITMAP src, int srcx, int srcy, /* brush */ BRUSH * brush, int bgcolour, int fgcolour) { /* This is potentially difficult to do in general. Until someone comes up with a more efficient way of doing it I am using cases. */ switch (opcode) { case 0x69: /* PDSxxn */ ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy); ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour); break; case 0xb8: /* PSDPxax */ ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy); ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); break; case 0xc0: /* PSa */ ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy); ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour); break; default: unimpl("triblt 0x%x\n", opcode); ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy); } } void ui_line(uint8 opcode, /* dest */ int startx, int starty, int endx, int endy, /* pen */ PEN * pen) { SET_FUNCTION(opcode); SET_FOREGROUND(pen->colour); XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy); ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc, startx - sw->xoffset, starty - sw->yoffset, endx - sw->xoffset, endy - sw->yoffset)); if (g_ownbackstore) XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy); RESET_FUNCTION(opcode); } void ui_rect( /* dest */ int x, int y, int cx, int cy, /* brush */ int colour) { SET_FOREGROUND(colour); FILL_RECTANGLE(x, y, cx, cy); } void ui_polygon(uint8 opcode, /* mode */ uint8 fillmode, /* dest */ RD_POINT * point, int npoints, /* brush */ BRUSH * brush, int bgcolour, int fgcolour) { uint8 style, i, ipattern[8]; Pixmap fill; SET_FUNCTION(opcode); switch (fillmode) { case ALTERNATE: XSetFillRule(g_display, g_gc, EvenOddRule); break; case WINDING: XSetFillRule(g_display, g_gc, WindingRule); break; default: unimpl("fill mode %d\n", fillmode); } if (brush) style = brush->style; else style = 0; switch (style) { case 0: /* Solid */ SET_FOREGROUND(fgcolour); FILL_POLYGON((XPoint *) point, npoints); break; case 2: /* Hatch */ fill = (Pixmap) ui_create_glyph(8, 8, hatch_patterns + brush->pattern[0] * 8); SET_FOREGROUND(fgcolour); SET_BACKGROUND(bgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); FILL_POLYGON((XPoint *) point, npoints); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); break; case 3: /* Pattern */ if (brush->bd == 0) /* rdp4 brush */ { for (i = 0; i != 8; i++) ipattern[7 - i] = brush->pattern[i]; fill = (Pixmap) ui_create_glyph(8, 8, ipattern); SET_FOREGROUND(bgcolour); SET_BACKGROUND(fgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); FILL_POLYGON((XPoint *) point, npoints); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); } else if (brush->bd->colour_code > 1) /* > 1 bpp */ { fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data); XSetFillStyle(g_display, g_gc, FillTiled); XSetTile(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); FILL_POLYGON((XPoint *) point, npoints); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_bitmap((RD_HBITMAP) fill); } else { fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data); SET_FOREGROUND(bgcolour); SET_BACKGROUND(fgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); FILL_POLYGON((XPoint *) point, npoints); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); } break; default: unimpl("brush %d\n", brush->style); } RESET_FUNCTION(opcode); } void ui_polyline(uint8 opcode, /* dest */ RD_POINT * points, int npoints, /* pen */ PEN * pen) { /* TODO: set join style */ SET_FUNCTION(opcode); SET_FOREGROUND(pen->colour); XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious); if (g_ownbackstore) XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints, CoordModePrevious); ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines, (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset)); RESET_FUNCTION(opcode); } void ui_ellipse(uint8 opcode, /* mode */ uint8 fillmode, /* dest */ int x, int y, int cx, int cy, /* brush */ BRUSH * brush, int bgcolour, int fgcolour) { uint8 style, i, ipattern[8]; Pixmap fill; SET_FUNCTION(opcode); if (brush) style = brush->style; else style = 0; switch (style) { case 0: /* Solid */ SET_FOREGROUND(fgcolour); DRAW_ELLIPSE(x, y, cx, cy, fillmode); break; case 2: /* Hatch */ fill = (Pixmap) ui_create_glyph(8, 8, hatch_patterns + brush->pattern[0] * 8); SET_FOREGROUND(fgcolour); SET_BACKGROUND(bgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); DRAW_ELLIPSE(x, y, cx, cy, fillmode); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); break; case 3: /* Pattern */ if (brush->bd == 0) /* rdp4 brush */ { for (i = 0; i != 8; i++) ipattern[7 - i] = brush->pattern[i]; fill = (Pixmap) ui_create_glyph(8, 8, ipattern); SET_FOREGROUND(bgcolour); SET_BACKGROUND(fgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); DRAW_ELLIPSE(x, y, cx, cy, fillmode); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); } else if (brush->bd->colour_code > 1) /* > 1 bpp */ { fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data); XSetFillStyle(g_display, g_gc, FillTiled); XSetTile(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); DRAW_ELLIPSE(x, y, cx, cy, fillmode); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_bitmap((RD_HBITMAP) fill); } else { fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data); SET_FOREGROUND(bgcolour); SET_BACKGROUND(fgcolour); XSetFillStyle(g_display, g_gc, FillOpaqueStippled); XSetStipple(g_display, g_gc, fill); XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); DRAW_ELLIPSE(x, y, cx, cy, fillmode); XSetFillStyle(g_display, g_gc, FillSolid); XSetTSOrigin(g_display, g_gc, 0, 0); ui_destroy_glyph((RD_HGLYPH) fill); } break; default: unimpl("brush %d\n", brush->style); } RESET_FUNCTION(opcode); } /* warning, this function only draws on wnd or backstore, not both */ void ui_draw_glyph(int mixmode, /* dest */ int x, int y, int cx, int cy, /* src */ RD_HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour) { SET_FOREGROUND(fgcolour); SET_BACKGROUND(bgcolour); XSetFillStyle(g_display, g_gc, (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled); XSetStipple(g_display, g_gc, (Pixmap) glyph); XSetTSOrigin(g_display, g_gc, x, y); FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); XSetFillStyle(g_display, g_gc, FillSolid); } #define DO_GLYPH(ttext,idx) \ {\ glyph = cache_get_font (font, ttext[idx]);\ if (!(flags & TEXT2_IMPLICIT_X))\ {\ xyoffset = ttext[++idx];\ if ((xyoffset & 0x80))\ {\ if (flags & TEXT2_VERTICAL)\ y += ttext[idx+1] | (ttext[idx+2] << 8);\ else\ x += ttext[idx+1] | (ttext[idx+2] << 8);\ idx += 2;\ }\ else\ {\ if (flags & TEXT2_VERTICAL)\ y += xyoffset;\ else\ x += xyoffset;\ }\ }\ if (glyph != NULL)\ {\ x1 = x + glyph->offset;\ y1 = y + glyph->baseline;\ XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\ XSetTSOrigin(g_display, g_gc, x1, y1);\ FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\ if (flags & TEXT2_IMPLICIT_X)\ x += glyph->width;\ }\ } void ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y, int clipx, int clipy, int clipcx, int clipcy, int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush, int bgcolour, int fgcolour, uint8 * text, uint8 length) { /* TODO: use brush appropriately */ FONTGLYPH *glyph; int i, j, xyoffset, x1, y1; DATABLOB *entry; SET_FOREGROUND(bgcolour); /* Sometimes, the boxcx value is something really large, like 32691. This makes XCopyArea fail with Xvnc. The code below is a quick fix. */ if (boxx + boxcx > g_width) boxcx = g_width - boxx; if (boxcx > 1) { FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy); } else if (mixmode == MIX_OPAQUE) { FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy); } SET_FOREGROUND(fgcolour); SET_BACKGROUND(bgcolour); XSetFillStyle(g_display, g_gc, FillStippled); /* Paint text, character by character */ for (i = 0; i < length;) { switch (text[i]) { case 0xff: /* At least two bytes needs to follow */ if (i + 3 > length) { warning("Skipping short 0xff command:"); for (j = 0; j < length; j++) fprintf(stderr, "%02x ", text[j]); fprintf(stderr, "\n"); i = length = 0; break; } cache_put_text(text[i + 1], text, text[i + 2]); i += 3; length -= i; /* this will move pointer from start to first character after FF command */ text = &(text[i]); i = 0; break; case 0xfe: /* At least one byte needs to follow */ if (i + 2 > length) { warning("Skipping short 0xfe command:"); for (j = 0; j < length; j++) fprintf(stderr, "%02x ", text[j]); fprintf(stderr, "\n"); i = length = 0; break; } entry = cache_get_text(text[i + 1]); if (entry->data != NULL) { if ((((uint8 *) (entry->data))[1] == 0) && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length)) { if (flags & TEXT2_VERTICAL) y += text[i + 2]; else x += text[i + 2]; } for (j = 0; j < entry->size; j++) DO_GLYPH(((uint8 *) (entry->data)), j); } if (i + 2 < length) i += 3; else i += 2; length -= i; /* this will move pointer from start to first character after FE command */ text = &(text[i]); i = 0; break; default: DO_GLYPH(text, i); i++; break; } } XSetFillStyle(g_display, g_gc, FillSolid); if (g_ownbackstore) { if (boxcx > 1) { XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx, boxy, boxcx, boxcy, boxx, boxy); ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_backstore, sw->wnd, g_gc, boxx, boxy, boxcx, boxcy, boxx - sw->xoffset, boxy - sw->yoffset)); } else { XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx, clipy, clipcx, clipcy, clipx, clipy); ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_backstore, sw->wnd, g_gc, clipx, clipy, clipcx, clipcy, clipx - sw->xoffset, clipy - sw->yoffset)); } } } void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) { Pixmap pix; XImage *image; if (g_ownbackstore) { image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap); exit_if_null(image); } else { pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth); XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0); image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap); exit_if_null(image); XFreePixmap(g_display, pix); } offset *= g_bpp / 8; cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data); XDestroyImage(image); } void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) { XImage *image; uint8 *data; offset *= g_bpp / 8; data = cache_get_desktop(offset, cx, cy, g_bpp / 8); if (data == NULL) return; image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0, (char *) data, cx, cy, g_bpp, 0); if (g_ownbackstore) { XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy); XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); } else { XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy); ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); } XFree(image); } /* these do nothing here but are used in uiports */ void ui_begin_update(void) { } void ui_end_update(void) { XFlush(g_display); } void ui_seamless_begin(RD_BOOL hidden) { if (!g_seamless_rdp) return; if (g_seamless_started) return; g_seamless_started = True; g_seamless_hidden = hidden; if (!hidden) ui_seamless_toggle(); if (g_seamless_spawn_cmd[0]) { seamless_send_spawn(g_seamless_spawn_cmd); g_seamless_spawn_cmd[0] = 0; } seamless_send_persistent(g_seamless_persistent_mode); } void ui_seamless_end() { /* Destroy all seamless windows */ while (g_seamless_windows) { XDestroyWindow(g_display, g_seamless_windows->wnd); sw_remove_window(g_seamless_windows); } g_seamless_started = False; g_seamless_active = False; g_seamless_hidden = False; } void ui_seamless_hide_desktop() { if (!g_seamless_rdp) return; if (!g_seamless_started) return; if (g_seamless_active) ui_seamless_toggle(); g_seamless_hidden = True; } void ui_seamless_unhide_desktop() { if (!g_seamless_rdp) return; if (!g_seamless_started) return; g_seamless_hidden = False; ui_seamless_toggle(); } void ui_seamless_toggle() { if (!g_seamless_rdp) return; if (!g_seamless_started) return; if (g_seamless_hidden) return; if (g_seamless_active) { /* Deactivate */ while (g_seamless_windows) { XDestroyWindow(g_display, g_seamless_windows->wnd); sw_remove_window(g_seamless_windows); } XMapWindow(g_display, g_wnd); } else { /* Activate */ XUnmapWindow(g_display, g_wnd); seamless_send_sync(); } g_seamless_active = !g_seamless_active; } void ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent, unsigned long flags) { Window wnd; XSetWindowAttributes attribs; XClassHint *classhints; XSizeHints *sizehints; XWMHints *wmhints; long input_mask; seamless_window *sw, *sw_parent; if (!g_seamless_active) return; /* Ignore CREATEs for existing windows */ sw = sw_get_window_by_id(id); if (sw) return; get_window_attribs(&attribs); wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth, InputOutput, g_visual, CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs); XStoreName(g_display, wnd, "SeamlessRDP"); ewmh_set_wm_name(wnd, "SeamlessRDP"); mwm_hide_decorations(wnd); classhints = XAllocClassHint(); if (classhints != NULL) { classhints->res_name = "rdesktop"; classhints->res_class = "SeamlessRDP"; XSetClassHint(g_display, wnd, classhints); XFree(classhints); } /* WM_NORMAL_HINTS */ sizehints = XAllocSizeHints(); if (sizehints != NULL) { sizehints->flags = USPosition; XSetWMNormalHints(g_display, wnd, sizehints); XFree(sizehints); } /* Parent-less transient windows */ if (parent == 0xFFFFFFFF) { XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen)); /* Some buggy wm:s (kwin) do not handle the above, so fake it using some other hints. */ ewmh_set_window_popup(wnd); } /* Normal transient windows */ else if (parent != 0x00000000) { sw_parent = sw_get_window_by_id(parent); if (sw_parent) XSetTransientForHint(g_display, wnd, sw_parent->wnd); else warning("ui_seamless_create_window: No parent window 0x%lx\n", parent); } if (flags & SEAMLESSRDP_CREATE_MODAL) { /* We do this to support buggy wm:s (*cough* metacity *cough*) somewhat at least */ if (parent == 0x00000000) XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen)); ewmh_set_window_modal(wnd); } if (flags & SEAMLESSRDP_CREATE_TOPMOST) { /* Make window always-on-top */ ewmh_set_window_above(wnd); } /* FIXME: Support for Input Context:s */ get_input_mask(&input_mask); input_mask |= PropertyChangeMask; XSelectInput(g_display, wnd, input_mask); /* handle the WM_DELETE_WINDOW protocol. */ XSetWMProtocols(g_display, wnd, &g_kill_atom, 1); sw = xmalloc(sizeof(seamless_window)); memset(sw, 0, sizeof(seamless_window)); sw->wnd = wnd; sw->id = id; sw->group = sw_find_group(group, False); sw->group->refcnt++; sw->state = SEAMLESSRDP_NOTYETMAPPED; sw->desktop = 0; sw->position_timer = xmalloc(sizeof(struct timeval)); timerclear(sw->position_timer); sw->outstanding_position = False; sw->outpos_serial = 0; sw->outpos_xoffset = sw->outpos_yoffset = 0; sw->outpos_width = sw->outpos_height = 0; sw->next = g_seamless_windows; g_seamless_windows = sw; /* WM_HINTS */ wmhints = XAllocWMHints(); if (wmhints) { wmhints->flags = WindowGroupHint; wmhints->window_group = sw->group->wnd; XSetWMHints(g_display, sw->wnd, wmhints); XFree(wmhints); } } void ui_seamless_destroy_window(unsigned long id, unsigned long flags) { seamless_window *sw; if (!g_seamless_active) return; sw = sw_get_window_by_id(id); if (!sw) { warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id); return; } XDestroyWindow(g_display, sw->wnd); sw_remove_window(sw); } void ui_seamless_destroy_group(unsigned long id, unsigned long flags) { seamless_window *sw, *sw_next; if (!g_seamless_active) return; for (sw = g_seamless_windows; sw; sw = sw_next) { sw_next = sw->next; if (sw->group->id == id) { XDestroyWindow(g_display, sw->wnd); sw_remove_window(sw); } } } void ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk, const char *data, int chunk_len) { seamless_window *sw; if (!g_seamless_active) return; sw = sw_get_window_by_id(id); if (!sw) { warning("ui_seamless_seticon: No information for window 0x%lx\n", id); return; } if (chunk == 0) { if (sw->icon_size) warning("ui_seamless_seticon: New icon started before previous completed\n"); if (strcmp(format, "RGBA") != 0) { warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format); return; } sw->icon_size = width * height * 4; if (sw->icon_size > 32 * 32 * 4) { warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size); sw->icon_size = 0; return; } sw->icon_offset = 0; } else { if (!sw->icon_size) return; } if (chunk_len > (sw->icon_size - sw->icon_offset)) { warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n", chunk_len, sw->icon_size - sw->icon_offset); sw->icon_size = 0; return; } memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len); sw->icon_offset += chunk_len; if (sw->icon_offset == sw->icon_size) { ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer); sw->icon_size = 0; } } void ui_seamless_delicon(unsigned long id, const char *format, int width, int height) { seamless_window *sw; if (!g_seamless_active) return; sw = sw_get_window_by_id(id); if (!sw) { warning("ui_seamless_seticon: No information for window 0x%lx\n", id); return; } if (strcmp(format, "RGBA") != 0) { warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format); return; } ewmh_del_icon(sw->wnd, width, height); } void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags) { seamless_window *sw; if (!g_seamless_active) return; sw = sw_get_window_by_id(id); if (!sw) { warning("ui_seamless_move_window: No information for window 0x%lx\n", id); return; } /* We ignore server updates until it has handled our request. */ if (sw->outstanding_position) return; if (!width || !height) /* X11 windows must be at least 1x1 */ return; /* If we move the window in a maximized state, then KDE won't accept restoration */ switch (sw->state) { case SEAMLESSRDP_MINIMIZED: case SEAMLESSRDP_MAXIMIZED: sw_update_position(sw); return; } sw->xoffset = x; sw->yoffset = y; sw->width = width; sw->height = height; /* FIXME: Perhaps use ewmh_net_moveresize_window instead */ XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height); } void ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags) { seamless_window *sw; XWindowChanges values; unsigned long restack_serial; unsigned int value_mask; if (!g_seamless_active) return; sw = sw_get_window_by_id(id); if (!sw) { warning("ui_seamless_restack_window: No information for window 0x%lx\n", id); return; } if (behind) { seamless_window *sw_behind; sw_behind = sw_get_window_by_id(behind); if (!sw_behind) { warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind); return; } values.stack_mode = Below; value_mask = CWStackMode | CWSibling; values.sibling = sw_behind->wnd; /* Avoid that topmost windows references non-topmost windows, and vice versa. */ if (ewmh_is_window_above(sw->wnd)) { if (!ewmh_is_window_above(sw_behind->wnd)) { /* Disallow, move to bottom of the topmost stack. */ values.stack_mode = Below; value_mask = CWStackMode; /* Not sibling */ } } else { if (ewmh_is_window_above(sw_behind->wnd)) { /* Move to top of non-topmost stack. */ values.stack_mode = Above; value_mask = CWStackMode; /* Not sibling */ } } } else { values.stack_mode = Above; value_mask = CWStackMode; } restack_serial = XNextRequest(g_display); XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display), value_mask, &values); sw_wait_configurenotify(sw->wnd, restack_serial); sw_restack_window(sw, behind); if (flags & SEAMLESSRDP_CREATE_TOPMOST) { /* Make window always-on-top */ ewmh_set_window_above(sw->wnd); } } void ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags) { seamless_window *sw; if (!g_seamless_active) return; sw = sw_get_window_by_id(id); if (!sw) { warning("ui_seamless_settitle: No information for window 0x%lx\n", id); return; } /* FIXME: Might want to convert the name for non-EWMH WMs */ XStoreName(g_display, sw->wnd, title); ewmh_set_wm_name(sw->wnd, title); } void ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags) { seamless_window *sw; if (!g_seamless_active) return; sw = sw_get_window_by_id(id); if (!sw) { warning("ui_seamless_setstate: No information for window 0x%lx\n", id); return; } switch (state) { case SEAMLESSRDP_NORMAL: case SEAMLESSRDP_MAXIMIZED: ewmh_change_state(sw->wnd, state); XMapWindow(g_display, sw->wnd); break; case SEAMLESSRDP_MINIMIZED: /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN the Window Manager should probably just ignore the request, since _NET_WM_STATE_HIDDEN is a function of some other aspect of the window such as minimization, rather than an independent state." Besides, XIconifyWindow is easier. */ if (sw->state == SEAMLESSRDP_NOTYETMAPPED) { XWMHints *hints; hints = XGetWMHints(g_display, sw->wnd); if (hints) { hints->flags |= StateHint; hints->initial_state = IconicState; XSetWMHints(g_display, sw->wnd, hints); XFree(hints); } XMapWindow(g_display, sw->wnd); } else XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display)); break; default: warning("SeamlessRDP: Invalid state %d\n", state); break; } sw->state = state; } void ui_seamless_syncbegin(unsigned long flags) { if (!g_seamless_active) return; /* Destroy all seamless windows */ while (g_seamless_windows) { XDestroyWindow(g_display, g_seamless_windows->wnd); sw_remove_window(g_seamless_windows); } } void ui_seamless_ack(unsigned int serial) { seamless_window *sw; for (sw = g_seamless_windows; sw; sw = sw->next) { if (sw->outstanding_position && (sw->outpos_serial == serial)) { sw->xoffset = sw->outpos_xoffset; sw->yoffset = sw->outpos_yoffset; sw->width = sw->outpos_width; sw->height = sw->outpos_height; sw->outstanding_position = False; /* Do a complete redraw of the window as part of the completion of the move. This is to remove any artifacts caused by our lack of synchronization. */ XCopyArea(g_display, g_backstore, sw->wnd, g_gc, sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0); break; } } } rdesktop-1.8.3/constants.h0000664000770100510440000003752312403571701014474 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Miscellaneous protocol constants Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ /* TCP port for Remote Desktop Protocol */ #define TCP_PORT_RDP 3389 #define DEFAULT_CODEPAGE "UTF-8" #define WINDOWS_CODEPAGE "UTF-16LE" /* ISO PDU codes */ enum ISO_PDU_CODE { ISO_PDU_CR = 0xE0, /* Connection Request */ ISO_PDU_CC = 0xD0, /* Connection Confirm */ ISO_PDU_DR = 0x80, /* Disconnect Request */ ISO_PDU_DT = 0xF0, /* Data */ ISO_PDU_ER = 0x70 /* Error */ }; /* RDP protocol negotiating constants */ enum RDP_NEG_TYPE_CODE { RDP_NEG_REQ = 1, RDP_NEG_RSP = 2, RDP_NEG_FAILURE = 3 }; enum RDP_NEG_REQ_CODE { PROTOCOL_RDP = 0, PROTOCOL_SSL = 1, PROTOCOL_HYBRID = 2 }; enum RDP_NEG_FAILURE_CODE { SSL_REQUIRED_BY_SERVER = 1, SSL_NOT_ALLOWED_BY_SERVER = 2, SSL_CERT_NOT_ON_SERVER = 3, INCONSISTENT_FLAGS = 4, HYBRID_REQUIRED_BY_SERVER = 5, SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 6 }; /* MCS PDU codes */ enum MCS_PDU_TYPE { MCS_EDRQ = 1, /* Erect Domain Request */ MCS_DPUM = 8, /* Disconnect Provider Ultimatum */ MCS_AURQ = 10, /* Attach User Request */ MCS_AUCF = 11, /* Attach User Confirm */ MCS_CJRQ = 14, /* Channel Join Request */ MCS_CJCF = 15, /* Channel Join Confirm */ MCS_SDRQ = 25, /* Send Data Request */ MCS_SDIN = 26 /* Send Data Indication */ }; #define MCS_CONNECT_INITIAL 0x7f65 #define MCS_CONNECT_RESPONSE 0x7f66 #define BER_TAG_BOOLEAN 1 #define BER_TAG_INTEGER 2 #define BER_TAG_OCTET_STRING 4 #define BER_TAG_RESULT 10 #define BER_TAG_SEQUENCE 16 #define BER_TAG_CONSTRUCTED 0x20 #define BER_TAG_CTXT_SPECIFIC 0x80 #define MCS_TAG_DOMAIN_PARAMS 0x30 #define MCS_GLOBAL_CHANNEL 1003 #define MCS_USERCHANNEL_BASE 1001 /* RDP secure transport constants */ #define SEC_RANDOM_SIZE 32 #define SEC_MODULUS_SIZE 64 #define SEC_MAX_MODULUS_SIZE 256 #define SEC_PADDING_SIZE 8 #define SEC_EXPONENT_SIZE 4 #define SEC_CLIENT_RANDOM 0x0001 #define SEC_ENCRYPT 0x0008 #define SEC_LOGON_INFO 0x0040 #define SEC_LICENCE_NEG 0x0080 #define SEC_REDIRECT_ENCRYPT 0x0C00 #define SEC_TAG_SRV_INFO 0x0c01 #define SEC_TAG_SRV_CRYPT 0x0c02 #define SEC_TAG_SRV_CHANNELS 0x0c03 #define SEC_TAG_CLI_INFO 0xc001 #define SEC_TAG_CLI_CRYPT 0xc002 #define SEC_TAG_CLI_CHANNELS 0xc003 #define SEC_TAG_CLI_CLUSTER 0xc004 #define SEC_TAG_PUBKEY 0x0006 #define SEC_TAG_KEYSIG 0x0008 #define SEC_RSA_MAGIC 0x31415352 /* RSA1 */ /* Client cluster constants */ #define SEC_CC_REDIRECTION_SUPPORTED 0x00000001 #define SEC_CC_REDIRECT_SESSIONID_FIELD_VALID 0x00000002 #define SEC_CC_REDIRECTED_SMARTCARD 0x00000040 #define SEC_CC_REDIRECT_VERSION_MASK 0x0000003c #define SEC_CC_REDIRECT_VERSION_3 0x02 #define SEC_CC_REDIRECT_VERSION_4 0x03 #define SEC_CC_REDIRECT_VERSION_5 0x04 #define SEC_CC_REDIRECT_VERSION_6 0x05 /* RDP licensing constants */ #define LICENCE_TOKEN_SIZE 10 #define LICENCE_HWID_SIZE 20 #define LICENCE_SIGNATURE_SIZE 16 #define LICENCE_TAG_REQUEST 0x01 #define LICENCE_TAG_PLATFORM_CHALLANGE 0x02 #define LICENCE_TAG_NEW_LICENCE 0x03 #define LICENCE_TAG_UPGRADE_LICENCE 0x04 #define LICENCE_TAG_LICENCE_INFO 0x12 #define LICENCE_TAG_NEW_LICENCE_REQUEST 0x13 #define LICENCE_TAG_PLATFORM_CHALLANGE_RESPONSE 0x15 #define LICENCE_TAG_ERROR_ALERT 0xff #define BB_CLIENT_USER_NAME_BLOB 0x000f #define BB_CLIENT_MACHINE_NAME_BLOB 0x0010 /* RDP PDU codes */ enum RDP_PDU_TYPE { RDP_PDU_DEMAND_ACTIVE = 1, RDP_PDU_CONFIRM_ACTIVE = 3, RDP_PDU_REDIRECT = 4, /* Standard Server Redirect */ RDP_PDU_DEACTIVATE = 6, RDP_PDU_DATA = 7, RDP_PDU_ENHANCED_REDIRECT = 10 /* Enhanced Server Redirect */ }; enum RDP_DATA_PDU_TYPE { RDP_DATA_PDU_UPDATE = 2, RDP_DATA_PDU_CONTROL = 20, RDP_DATA_PDU_POINTER = 27, RDP_DATA_PDU_INPUT = 28, RDP_DATA_PDU_SYNCHRONISE = 31, RDP_DATA_PDU_BELL = 34, RDP_DATA_PDU_CLIENT_WINDOW_STATUS = 35, RDP_DATA_PDU_LOGON = 38, /* PDUTYPE2_SAVE_SESSION_INFO */ RDP_DATA_PDU_FONT2 = 39, RDP_DATA_PDU_KEYBOARD_INDICATORS = 41, RDP_DATA_PDU_DISCONNECT = 47, RDP_DATA_PDU_AUTORECONNECT_STATUS = 50 }; enum RDP_SAVE_SESSION_PDU_TYPE { INFOTYPE_LOGON = 0, INFOTYPE_LOGON_LONG = 1, INFOTYPE_LOGON_PLAINNOTIFY = 2, INFOTYPE_LOGON_EXTENDED_INF = 3 }; enum RDP_LOGON_INFO_EXTENDED_TYPE { LOGON_EX_AUTORECONNECTCOOKIE = 1, LOGON_EX_LOGONERRORS = 2 }; enum RDP_CONTROL_PDU_TYPE { RDP_CTL_REQUEST_CONTROL = 1, RDP_CTL_GRANT_CONTROL = 2, RDP_CTL_DETACH = 3, RDP_CTL_COOPERATE = 4 }; enum RDP_UPDATE_PDU_TYPE { RDP_UPDATE_ORDERS = 0, RDP_UPDATE_BITMAP = 1, RDP_UPDATE_PALETTE = 2, RDP_UPDATE_SYNCHRONIZE = 3 }; enum RDP_POINTER_PDU_TYPE { RDP_POINTER_SYSTEM = 1, RDP_POINTER_MOVE = 3, RDP_POINTER_COLOR = 6, RDP_POINTER_CACHED = 7, RDP_POINTER_NEW = 8 }; enum RDP_SYSTEM_POINTER_TYPE { RDP_NULL_POINTER = 0, RDP_DEFAULT_POINTER = 0x7F00 }; enum RDP_INPUT_DEVICE { RDP_INPUT_SYNCHRONIZE = 0, RDP_INPUT_CODEPOINT = 1, RDP_INPUT_VIRTKEY = 2, RDP_INPUT_SCANCODE = 4, RDP_INPUT_MOUSE = 0x8001 }; /* Device flags */ #define KBD_FLAG_RIGHT 0x0001 #define KBD_FLAG_EXT 0x0100 #define KBD_FLAG_QUIET 0x1000 #define KBD_FLAG_DOWN 0x4000 #define KBD_FLAG_UP 0x8000 /* These are for synchronization; not for keystrokes */ #define KBD_FLAG_SCROLL 0x0001 #define KBD_FLAG_NUMLOCK 0x0002 #define KBD_FLAG_CAPITAL 0x0004 /* See T.128 */ #define RDP_KEYPRESS 0 #define RDP_KEYRELEASE (KBD_FLAG_DOWN | KBD_FLAG_UP) #define MOUSE_FLAG_MOVE 0x0800 #define MOUSE_FLAG_BUTTON1 0x1000 #define MOUSE_FLAG_BUTTON2 0x2000 #define MOUSE_FLAG_BUTTON3 0x4000 #define MOUSE_FLAG_BUTTON4 0x0280 #define MOUSE_FLAG_BUTTON5 0x0380 #define MOUSE_FLAG_DOWN 0x8000 /* Raster operation masks */ #define ROP2_S(rop3) (rop3 & 0xf) #define ROP2_P(rop3) ((rop3 & 0x3) | ((rop3 & 0x30) >> 2)) #define ROP2_COPY 0xc #define ROP2_XOR 0x6 #define ROP2_AND 0x8 #define ROP2_NXOR 0x9 #define ROP2_OR 0xe #define MIX_TRANSPARENT 0 #define MIX_OPAQUE 1 #define TEXT2_VERTICAL 0x04 #define TEXT2_IMPLICIT_X 0x20 #define ALTERNATE 1 #define WINDING 2 /* RDP bitmap cache (version 2) constants */ #define BMPCACHE2_C0_CELLS 0x78 #define BMPCACHE2_C1_CELLS 0x78 #define BMPCACHE2_C2_CELLS 0x150 #define BMPCACHE2_NUM_PSTCELLS 0x9f6 #define PDU_FLAG_FIRST 0x01 #define PDU_FLAG_LAST 0x02 /* RDP capabilities */ #define RDP_CAPSET_GENERAL 1 /* Maps to generalCapabilitySet in T.128 page 138 */ #define RDP_CAPLEN_GENERAL 0x18 #define OS_MAJOR_TYPE_UNIX 4 #define OS_MINOR_TYPE_XSERVER 7 #define RDP_CAPSET_BITMAP 2 #define RDP_CAPLEN_BITMAP 0x1C #define RDP_CAPSET_ORDER 3 #define RDP_CAPLEN_ORDER 0x58 #define ORDER_CAP_NEGOTIATE 2 #define ORDER_CAP_NOSUPPORT 4 #define RDP_CAPSET_BMPCACHE 4 #define RDP_CAPLEN_BMPCACHE 0x28 #define RDP_CAPSET_CONTROL 5 #define RDP_CAPLEN_CONTROL 0x0C #define RDP_CAPSET_ACTIVATE 7 #define RDP_CAPLEN_ACTIVATE 0x0C #define RDP_CAPSET_POINTER 8 #define RDP_CAPLEN_POINTER 0x08 #define RDP_CAPLEN_NEWPOINTER 0x0a #define RDP_CAPSET_SHARE 9 #define RDP_CAPLEN_SHARE 0x08 #define RDP_CAPSET_COLCACHE 10 #define RDP_CAPLEN_COLCACHE 0x08 #define RDP_CAPSET_BRUSHCACHE 15 #define RDP_CAPLEN_BRUSHCACHE 0x08 #define RDP_CAPSET_BMPCACHE2 19 #define RDP_CAPLEN_BMPCACHE2 0x28 #define BMPCACHE2_FLAG_PERSIST ((uint32)1<<31) #define RDP_SOURCE "MSTSC" /* Logon flags */ #define RDP_INFO_MOUSE 0x00000001 #define RDP_INFO_DISABLECTRLALTDEL 0x00000002 #define RDP_INFO_AUTOLOGON 0x00000008 #define RDP_INFO_UNICODE 0x00000010 #define RDP_INFO_MAXIMIZESHELL 0x00000020 #define RDP_INFO_COMPRESSION 0x00000080 /* mppc compression with 8kB histroy buffer */ #define RDP_INFO_ENABLEWINDOWSKEY 0x00000100 #define RDP_INFO_COMPRESSION2 0x00000200 /* rdp5 mppc compression with 64kB history buffer */ #define RDP_INFO_REMOTE_CONSOLE_AUDIO 0x00002000 #define RDP_INFO_PASSWORD_IS_SC_PIN 0x00040000 #define RDP5_DISABLE_NOTHING 0x00 #define RDP5_NO_WALLPAPER 0x01 #define RDP5_NO_FULLWINDOWDRAG 0x02 #define RDP5_NO_MENUANIMATIONS 0x04 #define RDP5_NO_THEMING 0x08 #define RDP5_NO_CURSOR_SHADOW 0x20 #define RDP5_NO_CURSORSETTINGS 0x40 /* disables cursor blinking */ /* compression types */ #define RDP_MPPC_BIG 0x01 #define RDP_MPPC_COMPRESSED 0x20 #define RDP_MPPC_RESET 0x40 #define RDP_MPPC_FLUSH 0x80 #define RDP_MPPC_DICT_SIZE 65536 #define RDP5_COMPRESSED 0x80 /* Keymap flags */ #define MapRightShiftMask (1<<0) #define MapLeftShiftMask (1<<1) #define MapShiftMask (MapRightShiftMask | MapLeftShiftMask) #define MapRightAltMask (1<<2) #define MapLeftAltMask (1<<3) #define MapAltGrMask MapRightAltMask #define MapRightCtrlMask (1<<4) #define MapLeftCtrlMask (1<<5) #define MapCtrlMask (MapRightCtrlMask | MapLeftCtrlMask) #define MapRightWinMask (1<<6) #define MapLeftWinMask (1<<7) #define MapWinMask (MapRightWinMask | MapLeftWinMask) #define MapNumLockMask (1<<8) #define MapCapsLockMask (1<<9) #define MapLocalStateMask (1<<10) #define MapInhibitMask (1<<11) #define MASK_ADD_BITS(var, mask) (var |= mask) #define MASK_REMOVE_BITS(var, mask) (var &= ~mask) #define MASK_HAS_BITS(var, mask) ((var & mask)>0) #define MASK_CHANGE_BIT(var, mask, active) (var = ((var & ~mask) | (active ? mask : 0))) /* Clipboard constants, "borrowed" from GCC system headers in the w32 cross compiler this is the CF_ set when WINVER is 0x0400 */ #ifndef CF_TEXT #define CF_TEXT 1 #define CF_BITMAP 2 #define CF_METAFILEPICT 3 #define CF_SYLK 4 #define CF_DIF 5 #define CF_TIFF 6 #define CF_OEMTEXT 7 #define CF_DIB 8 #define CF_PALETTE 9 #define CF_PENDATA 10 #define CF_RIFF 11 #define CF_WAVE 12 #define CF_UNICODETEXT 13 #define CF_ENHMETAFILE 14 #define CF_HDROP 15 #define CF_LOCALE 16 #define CF_MAX 17 #define CF_OWNERDISPLAY 128 #define CF_DSPTEXT 129 #define CF_DSPBITMAP 130 #define CF_DSPMETAFILEPICT 131 #define CF_DSPENHMETAFILE 142 #define CF_PRIVATEFIRST 512 #define CF_PRIVATELAST 767 #define CF_GDIOBJFIRST 768 #define CF_GDIOBJLAST 1023 #endif /* Sound format constants */ #define WAVE_FORMAT_PCM 1 #define WAVE_FORMAT_ADPCM 2 #define WAVE_FORMAT_ALAW 6 #define WAVE_FORMAT_MULAW 7 /* Virtual channel options */ #define CHANNEL_OPTION_INITIALIZED 0x80000000 #define CHANNEL_OPTION_ENCRYPT_RDP 0x40000000 #define CHANNEL_OPTION_COMPRESS_RDP 0x00800000 #define CHANNEL_OPTION_SHOW_PROTOCOL 0x00200000 /* NT status codes for RDPDR */ #define RD_STATUS_SUCCESS 0x00000000 #define RD_STATUS_NOT_IMPLEMENTED 0x00000001 #define RD_STATUS_PENDING 0x00000103 #define RD_STATUS_NO_MORE_FILES 0x80000006 #define RD_STATUS_DEVICE_PAPER_EMPTY 0x8000000e #define RD_STATUS_DEVICE_POWERED_OFF 0x8000000f #define RD_STATUS_DEVICE_OFF_LINE 0x80000010 #define RD_STATUS_DEVICE_BUSY 0x80000011 #define RD_STATUS_INVALID_HANDLE 0xc0000008 #define RD_STATUS_INVALID_PARAMETER 0xc000000d #define RD_STATUS_NO_SUCH_FILE 0xc000000f #define RD_STATUS_INVALID_DEVICE_REQUEST 0xc0000010 #define RD_STATUS_ACCESS_DENIED 0xc0000022 #define RD_STATUS_OBJECT_NAME_COLLISION 0xc0000035 #define RD_STATUS_DISK_FULL 0xc000007f #define RD_STATUS_FILE_IS_A_DIRECTORY 0xc00000ba #define RD_STATUS_NOT_SUPPORTED 0xc00000bb #define RD_STATUS_TIMEOUT 0xc0000102 #define RD_STATUS_NOTIFY_ENUM_DIR 0xc000010c #define RD_STATUS_CANCELLED 0xc0000120 #define RD_STATUS_DIRECTORY_NOT_EMPTY 0xc0000101 /* RDPSND constants */ #define TSSNDCAPS_ALIVE 0x00000001 #define TSSNDCAPS_VOLUME 0x00000002 /* RDPDR constants */ #define RDPDR_CTYP_CORE 0x4472 #define RDPDR_CTYP_PRN 0x5052 #define PAKID_CORE_SERVER_ANNOUNCE 0x496e #define PAKID_CORE_CLIENTID_CONFIRM 0x4343 #define PAKID_CORE_CLIENT_NAME 0x434e #define PAKID_CORE_DEVICE_LIST_ANNOUNCE 0x4441 #define PAKID_CORE_DEVICE_REPLY 0x6472 #define PAKID_CORE_DEVICE_IOREQUEST 0x4952 #define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943 #define PAKID_CORE_SERVER_CAPABILITY 0x5350 #define PAKID_CORE_CLIENT_CAPABILITY 0x4350 #define PAKID_CORE_DEVICELIST_REMOVE 0x444d #define PAKID_PRN_CACHE_DATA 0x5043 #define PAKID_CORE_USER_LOGGEDON 0x554c #define PAKID_PRN_USING_XPS 0x5543 #define RDPDR_MAX_DEVICES 0x10 #define DEVICE_TYPE_SERIAL 0x01 #define DEVICE_TYPE_PARALLEL 0x02 #define DEVICE_TYPE_PRINTER 0x04 #define DEVICE_TYPE_DISK 0x08 #define DEVICE_TYPE_SCARD 0x20 #define FILE_DIRECTORY_FILE 0x00000001 #define FILE_NON_DIRECTORY_FILE 0x00000040 #define FILE_COMPLETE_IF_OPLOCKED 0x00000100 #define FILE_DELETE_ON_CLOSE 0x00001000 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 /* RDP5 disconnect PDU */ #define exDiscReasonNoInfo 0x0000 #define exDiscReasonAPIInitiatedDisconnect 0x0001 #define exDiscReasonAPIInitiatedLogoff 0x0002 #define exDiscReasonServerIdleTimeout 0x0003 #define exDiscReasonServerLogonTimeout 0x0004 #define exDiscReasonReplacedByOtherConnection 0x0005 #define exDiscReasonOutOfMemory 0x0006 #define exDiscReasonServerDeniedConnection 0x0007 #define exDiscReasonServerDeniedConnectionFips 0x0008 #define exDiscReasonServerInsufficientPrivileges 0x0009 #define exDiscReasonServerFreshCredentialsRequired 0x000a #define exDiscReasonRPCInitiatedDisconnectByUser 0x000b #define exDiscReasonByUser 0x000c #define exDiscReasonLicenseInternal 0x0100 #define exDiscReasonLicenseNoLicenseServer 0x0101 #define exDiscReasonLicenseNoLicense 0x0102 #define exDiscReasonLicenseErrClientMsg 0x0103 #define exDiscReasonLicenseHwidDoesntMatchLicense 0x0104 #define exDiscReasonLicenseErrClientLicense 0x0105 #define exDiscReasonLicenseCantFinishProtocol 0x0106 #define exDiscReasonLicenseClientEndedProtocol 0x0107 #define exDiscReasonLicenseErrClientEncryption 0x0108 #define exDiscReasonLicenseCantUpgradeLicense 0x0109 #define exDiscReasonLicenseNoRemoteConnections 0x010a /* SeamlessRDP constants */ #define SEAMLESSRDP_NOTYETMAPPED -1 #define SEAMLESSRDP_NORMAL 0 #define SEAMLESSRDP_MINIMIZED 1 #define SEAMLESSRDP_MAXIMIZED 2 #define SEAMLESSRDP_POSITION_TIMER 200000 #define SEAMLESSRDP_CREATE_MODAL 0x0001 #define SEAMLESSRDP_CREATE_TOPMOST 0x0002 #define SEAMLESSRDP_HELLO_RECONNECT 0x0001 #define SEAMLESSRDP_HELLO_HIDDEN 0x0002 /* Smartcard constants */ #define SCARD_LOCK_TCP 0 #define SCARD_LOCK_SEC 1 #define SCARD_LOCK_CHANNEL 2 #define SCARD_LOCK_RDPDR 3 #define SCARD_LOCK_LAST 4 /* redirect flags, from [MS-RDPBCGR] 2.2.13.1 */ enum RDP_PDU_REDIRECT_FLAGS { PDU_REDIRECT_HAS_IP = 0x1, PDU_REDIRECT_HAS_LOAD_BALANCE_INFO = 0x2, PDU_REDIRECT_HAS_USERNAME = 0x4, PDU_REDIRECT_HAS_DOMAIN = 0x8, PDU_REDIRECT_HAS_PASSWORD = 0x10, PDU_REDIRECT_DONT_STORE_USERNAME = 0x20, PDU_REDIRECT_USE_SMARTCARD = 0x40, PDU_REDIRECT_INFORMATIONAL = 0x80, PDU_REDIRECT_HAS_TARGET_FQDN = 0x100, PDU_REDIRECT_HAS_TARGET_NETBIOS = 0x200, PDU_REDIRECT_HAS_TARGET_IP_ARRAY = 0x800 }; rdesktop-1.8.3/disk.h0000664000770100510440000001077711323031512013403 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Disk Redirection definitions Copyright (C) Jeroen Meijer 2003-2008 Copyright (C) Peter Astrand 2004-2008 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 3 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, see . */ #define FILE_ATTRIBUTE_READONLY 0x00000001 #define FILE_ATTRIBUTE_HIDDEN 0x00000002 #define FILE_ATTRIBUTE_SYSTEM 0x00000004 #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 #define FILE_ATTRIBUTE_ARCHIVE 0x00000020 #define FILE_ATTRIBUTE_DEVICE 0x00000040 #define FILE_ATTRIBUTE_UNKNOWNXXX0 0x00000060 /* ??? ACTION i.e. 0x860 == compress this file ? */ #define FILE_ATTRIBUTE_NORMAL 0x00000080 #define FILE_ATTRIBUTE_TEMPORARY 0x00000100 #define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 #define FILE_ATTRIBUTE_COMPRESSED 0x00000800 #define FILE_ATTRIBUTE_OFFLINE 0x00001000 #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 #define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 #define FILE_FLAG_OPEN_NO_RECALL 0x00100000 #define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000 #define FILE_FLAG_POSIX_SEMANTICS 0x01000000 #define FILE_FLAG_BACKUP_SEMANTICS 0x02000000 /* sometimes used to create a directory */ #define FILE_FLAG_DELETE_ON_CLOSE 0x04000000 #define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000 #define FILE_FLAG_RANDOM_ACCESS 0x10000000 #define FILE_FLAG_NO_BUFFERING 0x20000000 #define FILE_FLAG_OVERLAPPED 0x40000000 #define FILE_FLAG_WRITE_THROUGH 0x80000000 #define FILE_SHARE_READ 0x01 #define FILE_SHARE_WRITE 0x02 #define FILE_SHARE_DELETE 0x04 #define FILE_BASIC_INFORMATION 0x04 #define FILE_STANDARD_INFORMATION 0x05 #define FS_CASE_SENSITIVE 0x00000001 #define FS_CASE_IS_PRESERVED 0x00000002 #define FS_UNICODE_STORED_ON_DISK 0x00000004 #define FS_PERSISTENT_ACLS 0x00000008 #define FS_FILE_COMPRESSION 0x00000010 #define FS_VOLUME_QUOTAS 0x00000020 #define FS_SUPPORTS_SPARSE_FILES 0x00000040 #define FS_SUPPORTS_REPARSE_POINTS 0x00000080 #define FS_SUPPORTS_REMOTE_STORAGE 0X00000100 #define FS_VOL_IS_COMPRESSED 0x00008000 #define FILE_READ_ONLY_VOLUME 0x00080000 #define OPEN_EXISTING 1 #define CREATE_NEW 2 #define OPEN_ALWAYS 3 #define TRUNCATE_EXISTING 4 #define CREATE_ALWAYS 5 #define GENERIC_READ 0x80000000 #define GENERIC_WRITE 0x40000000 #define GENERIC_EXECUTE 0x20000000 #define GENERIC_ALL 0x10000000 #define ERROR_FILE_NOT_FOUND 2L #define ERROR_ALREADY_EXISTS 183L #define MAX_OPEN_FILES 0x100 typedef enum _FILE_INFORMATION_CLASS { FileDirectoryInformation = 1, FileFullDirectoryInformation, FileBothDirectoryInformation, FileBasicInformation, FileStandardInformation, FileInternalInformation, FileEaInformation, FileAccessInformation, FileNameInformation, FileRenameInformation, FileLinkInformation, FileNamesInformation, FileDispositionInformation, FilePositionInformation, FileFullEaInformation, FileModeInformation, FileAlignmentInformation, FileAllInformation, FileAllocationInformation, FileEndOfFileInformation, FileAlternateNameInformation, FileStreamInformation, FilePipeInformation, FilePipeLocalInformation, FilePipeRemoteInformation, FileMailslotQueryInformation, FileMailslotSetInformation, FileCompressionInformation, FileCopyOnWriteInformation, FileCompletionInformation, FileMoveClusterInformation, FileOleClassIdInformation, FileOleStateBitsInformation, FileNetworkOpenInformation, FileObjectIdInformation, FileOleAllInformation, FileOleDirectoryInformation, FileContentIndexInformation, FileInheritContentIndexInformation, FileOleInformation, FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef enum _FSINFOCLASS { FileFsVolumeInformation = 1, FileFsLabelInformation, FileFsSizeInformation, FileFsDeviceInformation, FileFsAttributeInformation, FileFsControlInformation, FileFsFullSizeInformation, FileFsObjectIdInformation, FileFsDriverPathInformation, FileFsMaximumInformation } FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; rdesktop-1.8.3/orders.h0000664000770100510440000001320111323031512013730 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. RDP order processing Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ #define RDP_ORDER_STANDARD 0x01 #define RDP_ORDER_SECONDARY 0x02 #define RDP_ORDER_BOUNDS 0x04 #define RDP_ORDER_CHANGE 0x08 #define RDP_ORDER_DELTA 0x10 #define RDP_ORDER_LASTBOUNDS 0x20 #define RDP_ORDER_SMALL 0x40 #define RDP_ORDER_TINY 0x80 enum RDP_ORDER_TYPE { RDP_ORDER_DESTBLT = 0, RDP_ORDER_PATBLT = 1, RDP_ORDER_SCREENBLT = 2, RDP_ORDER_LINE = 9, RDP_ORDER_RECT = 10, RDP_ORDER_DESKSAVE = 11, RDP_ORDER_MEMBLT = 13, RDP_ORDER_TRIBLT = 14, RDP_ORDER_POLYGON = 20, RDP_ORDER_POLYGON2 = 21, RDP_ORDER_POLYLINE = 22, RDP_ORDER_ELLIPSE = 25, RDP_ORDER_ELLIPSE2 = 26, RDP_ORDER_TEXT2 = 27 }; enum RDP_SECONDARY_ORDER_TYPE { RDP_ORDER_RAW_BMPCACHE = 0, RDP_ORDER_COLCACHE = 1, RDP_ORDER_BMPCACHE = 2, RDP_ORDER_FONTCACHE = 3, RDP_ORDER_RAW_BMPCACHE2 = 4, RDP_ORDER_BMPCACHE2 = 5, RDP_ORDER_BRUSHCACHE = 7 }; typedef struct _DESTBLT_ORDER { sint16 x; sint16 y; sint16 cx; sint16 cy; uint8 opcode; } DESTBLT_ORDER; typedef struct _PATBLT_ORDER { sint16 x; sint16 y; sint16 cx; sint16 cy; uint8 opcode; uint32 bgcolour; uint32 fgcolour; BRUSH brush; } PATBLT_ORDER; typedef struct _SCREENBLT_ORDER { sint16 x; sint16 y; sint16 cx; sint16 cy; uint8 opcode; sint16 srcx; sint16 srcy; } SCREENBLT_ORDER; typedef struct _LINE_ORDER { uint16 mixmode; sint16 startx; sint16 starty; sint16 endx; sint16 endy; uint32 bgcolour; uint8 opcode; PEN pen; } LINE_ORDER; typedef struct _RECT_ORDER { sint16 x; sint16 y; sint16 cx; sint16 cy; uint32 colour; } RECT_ORDER; typedef struct _DESKSAVE_ORDER { uint32 offset; sint16 left; sint16 top; sint16 right; sint16 bottom; uint8 action; } DESKSAVE_ORDER; typedef struct _TRIBLT_ORDER { uint8 colour_table; uint8 cache_id; sint16 x; sint16 y; sint16 cx; sint16 cy; uint8 opcode; sint16 srcx; sint16 srcy; uint32 bgcolour; uint32 fgcolour; BRUSH brush; uint16 cache_idx; uint16 unknown; } TRIBLT_ORDER; typedef struct _MEMBLT_ORDER { uint8 colour_table; uint8 cache_id; sint16 x; sint16 y; sint16 cx; sint16 cy; uint8 opcode; sint16 srcx; sint16 srcy; uint16 cache_idx; } MEMBLT_ORDER; #define MAX_DATA 256 typedef struct _POLYGON_ORDER { sint16 x; sint16 y; uint8 opcode; uint8 fillmode; uint32 fgcolour; uint8 npoints; uint8 datasize; uint8 data[MAX_DATA]; } POLYGON_ORDER; typedef struct _POLYGON2_ORDER { sint16 x; sint16 y; uint8 opcode; uint8 fillmode; uint32 bgcolour; uint32 fgcolour; BRUSH brush; uint8 npoints; uint8 datasize; uint8 data[MAX_DATA]; } POLYGON2_ORDER; typedef struct _POLYLINE_ORDER { sint16 x; sint16 y; uint8 opcode; uint32 fgcolour; uint8 lines; uint8 datasize; uint8 data[MAX_DATA]; } POLYLINE_ORDER; typedef struct _ELLIPSE_ORDER { sint16 left; sint16 top; sint16 right; sint16 bottom; uint8 opcode; uint8 fillmode; uint32 fgcolour; } ELLIPSE_ORDER; typedef struct _ELLIPSE2_ORDER { sint16 left; sint16 top; sint16 right; sint16 bottom; uint8 opcode; uint8 fillmode; BRUSH brush; uint32 bgcolour; uint32 fgcolour; } ELLIPSE2_ORDER; #define MAX_TEXT 256 typedef struct _TEXT2_ORDER { uint8 font; uint8 flags; uint8 opcode; uint8 mixmode; uint32 bgcolour; uint32 fgcolour; sint16 clipleft; sint16 cliptop; sint16 clipright; sint16 clipbottom; sint16 boxleft; sint16 boxtop; sint16 boxright; sint16 boxbottom; BRUSH brush; sint16 x; sint16 y; uint8 length; uint8 text[MAX_TEXT]; } TEXT2_ORDER; typedef struct _RDP_ORDER_STATE { uint8 order_type; BOUNDS bounds; DESTBLT_ORDER destblt; PATBLT_ORDER patblt; SCREENBLT_ORDER screenblt; LINE_ORDER line; RECT_ORDER rect; DESKSAVE_ORDER desksave; MEMBLT_ORDER memblt; TRIBLT_ORDER triblt; POLYGON_ORDER polygon; POLYGON2_ORDER polygon2; POLYLINE_ORDER polyline; ELLIPSE_ORDER ellipse; ELLIPSE2_ORDER ellipse2; TEXT2_ORDER text2; } RDP_ORDER_STATE; typedef struct _RDP_RAW_BMPCACHE_ORDER { uint8 cache_id; uint8 pad1; uint8 width; uint8 height; uint8 bpp; uint16 bufsize; uint16 cache_idx; uint8 *data; } RDP_RAW_BMPCACHE_ORDER; typedef struct _RDP_BMPCACHE_ORDER { uint8 cache_id; uint8 pad1; uint8 width; uint8 height; uint8 bpp; uint16 bufsize; uint16 cache_idx; uint16 pad2; uint16 size; uint16 row_size; uint16 final_size; uint8 *data; } RDP_BMPCACHE_ORDER; /* RDP_BMPCACHE2_ORDER */ #define ID_MASK 0x0007 #define MODE_MASK 0x0038 #define SQUARE 0x0080 #define PERSIST 0x0100 #define FLAG_51_UNKNOWN 0x0800 #define MODE_SHIFT 3 #define LONG_FORMAT 0x80 #define BUFSIZE_MASK 0x3FFF /* or 0x1FFF? */ #define MAX_GLYPH 32 typedef struct _RDP_FONT_GLYPH { uint16 character; uint16 unknown; uint16 baseline; uint16 width; uint16 height; uint8 data[MAX_GLYPH]; } RDP_FONT_GLYPH; #define MAX_GLYPHS 256 typedef struct _RDP_FONTCACHE_ORDER { uint8 font; uint8 nglyphs; RDP_FONT_GLYPH glyphs[MAX_GLYPHS]; } RDP_FONTCACHE_ORDER; typedef struct _RDP_COLCACHE_ORDER { uint8 cache_id; COLOURMAP map; } RDP_COLCACHE_ORDER; rdesktop-1.8.3/parse.h0000664000770100510440000000723612051147770013574 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Parsing primitives Copyright (C) Matthew Chapman 1999-2008 Copyright 2012 Henrik Andersson for Cendio AB 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 3 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, see . */ /* Parser state */ typedef struct stream { unsigned char *p; unsigned char *end; unsigned char *data; unsigned int size; /* Offsets of various headers */ unsigned char *iso_hdr; unsigned char *mcs_hdr; unsigned char *sec_hdr; unsigned char *rdp_hdr; unsigned char *channel_hdr; } *STREAM; #define s_push_layer(s,h,n) { (s)->h = (s)->p; (s)->p += n; } #define s_pop_layer(s,h) (s)->p = (s)->h; #define s_mark_end(s) (s)->end = (s)->p; #define s_check(s) ((s)->p <= (s)->end) #define s_check_rem(s,n) ((s)->p + n <= (s)->end) #define s_check_end(s) ((s)->p == (s)->end) #define s_length(s) ((s)->end - (s)->data) #define s_reset(s) ((s)->end = (s)->p = (s)->data) #if defined(L_ENDIAN) && !defined(NEED_ALIGN) #define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; } #define in_uint32_le(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; } #define out_uint16_le(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; } #define out_uint32_le(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; } #else #define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; } #define in_uint32_le(s,v) { in_uint16_le(s,v) \ v += *((s)->p++) << 16; v += *((s)->p++) << 24; } #define out_uint16_le(s,v) { *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; } #define out_uint32_le(s,v) { out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); } #endif #if defined(B_ENDIAN) && !defined(NEED_ALIGN) #define in_uint16_be(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; } #define in_uint32_be(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; } #define out_uint16_be(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; } #define out_uint32_be(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; } #define B_ENDIAN_PREFERRED #define in_uint16(s,v) in_uint16_be(s,v) #define in_uint32(s,v) in_uint32_be(s,v) #define out_uint16(s,v) out_uint16_be(s,v) #define out_uint32(s,v) out_uint32_be(s,v) #else #define in_uint16_be(s,v) { v = *((s)->p++); next_be(s,v); } #define in_uint32_be(s,v) { in_uint16_be(s,v); next_be(s,v); next_be(s,v); } #define out_uint16_be(s,v) { *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; } #define out_uint32_be(s,v) { out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); } #endif #ifndef B_ENDIAN_PREFERRED #define in_uint16(s,v) in_uint16_le(s,v) #define in_uint32(s,v) in_uint32_le(s,v) #define out_uint16(s,v) out_uint16_le(s,v) #define out_uint32(s,v) out_uint32_le(s,v) #endif #define in_uint8(s,v) v = *((s)->p++); #define in_uint8p(s,v,n) { v = (s)->p; (s)->p += n; } #define in_uint8a(s,v,n) { memcpy(v,(s)->p,n); (s)->p += n; } #define in_uint8s(s,n) (s)->p += n; #define out_uint8(s,v) *((s)->p++) = v; #define out_uint8p(s,v,n) { memcpy((s)->p,v,n); (s)->p += n; } #define out_uint8a(s,v,n) out_uint8p(s,v,n); #define out_uint8s(s,n) { memset((s)->p,0,n); (s)->p += n; } #define next_be(s,v) v = ((v) << 8) + *((s)->p++); rdesktop-1.8.3/proto.h0000664000770100510440000004033312404306606013615 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ #ifndef RDESKTOP_PROTO_H #define RDESKTOP_PROTO_H /* *INDENT-OFF* */ #ifdef __cplusplus extern "C" { #endif /* *INDENT-ON* */ /* utils.c */ char *utils_string_escape(const char *str); char *utils_string_unescape(const char *str); int utils_locale_to_utf8(const char *src, size_t is, char *dest, size_t os); int utils_mkdir_safe(const char *path, int mask); int utils_mkdir_p(const char *path, int mask); /* bitmap.c */ RD_BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp); /* cache.c */ void cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count); void cache_bump_bitmap(uint8 id, uint16 idx, int bump); void cache_evict_bitmap(uint8 id); RD_HBITMAP cache_get_bitmap(uint8 id, uint16 idx); void cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap); void cache_save_state(void); FONTGLYPH *cache_get_font(uint8 font, uint16 character); void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap); DATABLOB *cache_get_text(uint8 cache_id); void cache_put_text(uint8 cache_id, void *data, int length); uint8 *cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel); void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data); RD_HCURSOR cache_get_cursor(uint16 cache_idx); void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor); BRUSHDATA *cache_get_brush_data(uint8 colour_code, uint8 idx); void cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data); /* channels.c */ VCHANNEL *channel_register(char *name, uint32 flags, void (*callback) (STREAM)); STREAM channel_init(VCHANNEL * channel, uint32 length); void channel_send(STREAM s, VCHANNEL * channel); void channel_process(STREAM s, uint16 mcs_channel); /* cliprdr.c */ void cliprdr_send_simple_native_format_announce(uint32 format); void cliprdr_send_native_format_announce(uint8 * formats_data, uint32 formats_data_length); void cliprdr_send_data_request(uint32 format); void cliprdr_send_data(uint8 * data, uint32 length); void cliprdr_set_mode(const char *optarg); RD_BOOL cliprdr_init(void); /* ctrl.c */ int ctrl_init(const char *user, const char *domain, const char *host); void ctrl_cleanup(); RD_BOOL ctrl_is_slave(); int ctrl_send_command(const char *cmd, const char *args); void ctrl_add_fds(int *n, fd_set * rfds); void ctrl_check_fds(fd_set * rfds, fd_set * wfds); /* disk.c */ int disk_enum_devices(uint32 * id, char *optarg); RD_NTSTATUS disk_query_information(RD_NTHANDLE handle, uint32 info_class, STREAM out); RD_NTSTATUS disk_set_information(RD_NTHANDLE handle, uint32 info_class, STREAM in, STREAM out); RD_NTSTATUS disk_check_notify(RD_NTHANDLE handle); RD_NTSTATUS disk_create_notify(RD_NTHANDLE handle, uint32 info_class); RD_NTSTATUS disk_query_volume_information(RD_NTHANDLE handle, uint32 info_class, STREAM out); RD_NTSTATUS disk_query_directory(RD_NTHANDLE handle, uint32 info_class, char *pattern, STREAM out); /* mppc.c */ int mppc_expand(uint8 * data, uint32 clen, uint8 ctype, uint32 * roff, uint32 * rlen); /* ewmhints.c */ int get_current_workarea(uint32 * x, uint32 * y, uint32 * width, uint32 * height); void ewmh_init(void); /* iso.c */ STREAM iso_init(int length); void iso_send(STREAM s); STREAM iso_recv(uint8 * rdpver); RD_BOOL iso_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol); void iso_disconnect(void); void iso_reset_state(void); /* cssp.c */ RD_BOOL cssp_connect(char *server, char *user, char *domain, char *password, STREAM s); /* licence.c */ void licence_process(STREAM s); /* mcs.c */ STREAM mcs_init(int length); void mcs_send_to_channel(STREAM s, uint16 channel); void mcs_send(STREAM s); STREAM mcs_recv(uint16 * channel, uint8 * rdpver); RD_BOOL mcs_connect_start(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol); RD_BOOL mcs_connect_finalize(STREAM s); void mcs_disconnect(void); void mcs_reset_state(void); /* orders.c */ void process_orders(STREAM s, uint16 num_orders); void reset_order_state(void); /* parallel.c */ int parallel_enum_devices(uint32 * id, char *optarg); /* printer.c */ int printer_enum_devices(uint32 * id, char *optarg); /* printercache.c */ int printercache_load_blob(char *printer_name, uint8 ** data); void printercache_process(STREAM s); /* pstcache.c */ void pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp); RD_BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx); RD_BOOL pstcache_save_bitmap(uint8 cache_id, uint16 cache_idx, uint8 * key, uint8 width, uint8 height, uint16 length, uint8 * data); int pstcache_enumerate(uint8 id, HASH_KEY * keylist); RD_BOOL pstcache_init(uint8 cache_id); /* rdesktop.c */ int main(int argc, char *argv[]); void generate_random(uint8 * random); void *xmalloc(int size); void exit_if_null(void *ptr); char *xstrdup(const char *s); void *xrealloc(void *oldmem, size_t size); void xfree(void *mem); void error(char *format, ...); void warning(char *format, ...); void unimpl(char *format, ...); void hexdump(unsigned char *p, unsigned int len); char *next_arg(char *src, char needle); void toupper_str(char *p); RD_BOOL str_startswith(const char *s, const char *prefix); RD_BOOL str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data); RD_BOOL subprocess(char *const argv[], str_handle_lines_t linehandler, void *data); char *l_to_a(long N, int base); int load_licence(unsigned char **data); void save_licence(unsigned char *data, int length); void rd_create_ui(void); RD_BOOL rd_pstcache_mkdir(void); int rd_open_file(char *filename); void rd_close_file(int fd); int rd_read_file(int fd, void *ptr, int len); int rd_write_file(int fd, void *ptr, int len); int rd_lseek_file(int fd, int offset); RD_BOOL rd_lock_file(int fd, int start, int len); /* rdp5.c */ void rdp5_process(STREAM s); /* rdp.c */ void rdp_out_unistr(STREAM s, char *string, int len); void rdp_in_unistr(STREAM s, int in_len, char **string, uint32 * str_size); void rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 param1, uint16 param2); void rdp_send_client_window_status(int status); void process_colour_pointer_pdu(STREAM s); void process_new_pointer_pdu(STREAM s); void process_cached_pointer_pdu(STREAM s); void process_system_pointer_pdu(STREAM s); void process_bitmap_updates(STREAM s); void process_palette(STREAM s); void process_disconnect_pdu(STREAM s, uint32 * ext_disc_reason); void rdp_main_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason); RD_BOOL rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason); RD_BOOL rdp_connect(char *server, uint32 flags, char *domain, char *password, char *command, char *directory, RD_BOOL reconnect); void rdp_reset_state(void); void rdp_disconnect(void); /* rdpdr.c */ int get_device_index(RD_NTHANDLE handle); void convert_to_unix_filename(char *filename); void rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer, uint32 length); RD_BOOL rdpdr_init(); void rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, RD_BOOL * timeout); struct async_iorequest *rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq); void rdpdr_check_fds(fd_set * rfds, fd_set * wfds, RD_BOOL timed_out); RD_BOOL rdpdr_abort_io(uint32 fd, uint32 major, RD_NTSTATUS status); /* rdpsnd.c */ void rdpsnd_record(const void *data, unsigned int size); RD_BOOL rdpsnd_init(char *optarg); void rdpsnd_show_help(void); void rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv); void rdpsnd_check_fds(fd_set * rfds, fd_set * wfds); struct audio_packet *rdpsnd_queue_current_packet(void); RD_BOOL rdpsnd_queue_empty(void); void rdpsnd_queue_next(unsigned long completed_in_us); int rdpsnd_queue_next_tick(void); void rdpsnd_reset_state(void); /* secure.c */ void sec_hash_to_string(char *out, int out_size, uint8 * in, int in_size); void sec_hash_sha1_16(uint8 * out, uint8 * in, uint8 * salt1); void sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt); void sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2); void buf_out_uint32(uint8 * buffer, uint32 value); void sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * data, int datalen); void sec_decrypt(uint8 * data, int length); STREAM sec_init(uint32 flags, int maxlen); void sec_send_to_channel(STREAM s, uint32 flags, uint16 channel); void sec_send(STREAM s, uint32 flags); void sec_process_mcs_data(STREAM s); STREAM sec_recv(uint8 * rdpver); RD_BOOL sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect); void sec_disconnect(void); void sec_reset_state(void); /* serial.c */ int serial_enum_devices(uint32 * id, char *optarg); RD_BOOL serial_get_event(RD_NTHANDLE handle, uint32 * result); RD_BOOL serial_get_timeout(RD_NTHANDLE handle, uint32 length, uint32 * timeout, uint32 * itv_timeout); /* tcp.c */ STREAM tcp_init(uint32 maxlen); void tcp_send(STREAM s); STREAM tcp_recv(STREAM s, uint32 length); RD_BOOL tcp_connect(char *server); void tcp_disconnect(void); char *tcp_get_address(void); RD_BOOL tcp_is_connected(void); void tcp_reset_state(void); RD_BOOL tcp_tls_connect(void); RD_BOOL tcp_tls_get_server_pubkey(STREAM s); void tcp_run_ui(RD_BOOL run); /* asn.c */ RD_BOOL ber_in_header(STREAM s, int *tagval, int *length); void ber_out_header(STREAM s, int tagval, int length); RD_BOOL ber_parse_header(STREAM s, int tagval, int *length); void ber_out_integer(STREAM s, int value); /* xclip.c */ void ui_clip_format_announce(uint8 * data, uint32 length); void ui_clip_handle_data(uint8 * data, uint32 length); void ui_clip_request_failed(void); void ui_clip_request_data(uint32 format); void ui_clip_sync(void); void ui_clip_set_mode(const char *optarg); void xclip_init(void); void xclip_deinit(void); /* xkeymap.c */ RD_BOOL xkeymap_from_locale(const char *locale); FILE *xkeymap_open(const char *filename); void xkeymap_init(void); RD_BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed); key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state); void xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time, RD_BOOL pressed, uint8 nesting); uint16 xkeymap_translate_button(unsigned int button); char *get_ksname(uint32 keysym); void save_remote_modifiers(uint8 scancode); void restore_remote_modifiers(uint32 ev_time, uint8 scancode); void ensure_remote_modifiers(uint32 ev_time, key_translation tr); unsigned int read_keyboard_state(void); uint16 ui_get_numlock_state(unsigned int state); void reset_modifier_keys(void); void rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode); /* xwin.c */ RD_BOOL get_key_state(unsigned int state, uint32 keysym); RD_BOOL ui_init(void); void ui_init_connection(void); void ui_deinit(void); RD_BOOL ui_create_window(void); void ui_resize_window(void); void ui_destroy_window(void); RD_BOOL ui_have_window(void); void xwin_toggle_fullscreen(void); int ui_select(int rdp_socket); void ui_move_pointer(int x, int y); RD_HBITMAP ui_create_bitmap(int width, int height, uint8 * data); void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data); void ui_destroy_bitmap(RD_HBITMAP bmp); RD_HGLYPH ui_create_glyph(int width, int height, uint8 * data); void ui_destroy_glyph(RD_HGLYPH glyph); RD_HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 * andmask, uint8 * xormask, int bpp); void ui_set_cursor(RD_HCURSOR cursor); void ui_destroy_cursor(RD_HCURSOR cursor); void ui_set_null_cursor(void); RD_HCOLOURMAP ui_create_colourmap(COLOURMAP * colours); void ui_destroy_colourmap(RD_HCOLOURMAP map); void ui_set_colourmap(RD_HCOLOURMAP map); void ui_set_clip(int x, int y, int cx, int cy); void ui_reset_clip(void); void ui_bell(void); void ui_destblt(uint8 opcode, int x, int y, int cx, int cy); void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, int fgcolour); void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy); void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, RD_HBITMAP src, int srcx, int srcy); void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, RD_HBITMAP src, int srcx, int srcy, BRUSH * brush, int bgcolour, int fgcolour); void ui_line(uint8 opcode, int startx, int starty, int endx, int endy, PEN * pen); void ui_rect(int x, int y, int cx, int cy, int colour); void ui_polygon(uint8 opcode, uint8 fillmode, RD_POINT * point, int npoints, BRUSH * brush, int bgcolour, int fgcolour); void ui_polyline(uint8 opcode, RD_POINT * points, int npoints, PEN * pen); void ui_ellipse(uint8 opcode, uint8 fillmode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, int fgcolour); void ui_draw_glyph(int mixmode, int x, int y, int cx, int cy, RD_HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour); void ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y, int clipx, int clipy, int clipcx, int clipcy, int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush, int bgcolour, int fgcolour, uint8 * text, uint8 length); void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy); void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy); void ui_begin_update(void); void ui_end_update(void); void ui_seamless_begin(RD_BOOL hidden); void ui_seamless_end(); void ui_seamless_hide_desktop(void); void ui_seamless_unhide_desktop(void); void ui_seamless_toggle(void); void ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent, unsigned long flags); void ui_seamless_destroy_window(unsigned long id, unsigned long flags); void ui_seamless_destroy_group(unsigned long id, unsigned long flags); void ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk, const char *data, int chunk_len); void ui_seamless_delicon(unsigned long id, const char *format, int width, int height); void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags); void ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags); void ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags); void ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags); void ui_seamless_syncbegin(unsigned long flags); void ui_seamless_ack(unsigned int serial); /* lspci.c */ RD_BOOL lspci_init(void); /* seamless.c */ RD_BOOL seamless_init(void); void seamless_reset_state(void); unsigned int seamless_send_sync(void); unsigned int seamless_send_state(unsigned long id, unsigned int state, unsigned long flags); unsigned int seamless_send_position(unsigned long id, int x, int y, int width, int height, unsigned long flags); void seamless_select_timeout(struct timeval *tv); unsigned int seamless_send_zchange(unsigned long id, unsigned long below, unsigned long flags); unsigned int seamless_send_focus(unsigned long id, unsigned long flags); unsigned int seamless_send_destroy(unsigned long id); unsigned int seamless_send_spawn(char *cmd); unsigned int seamless_send_persistent(RD_BOOL); /* scard.c */ void scard_lock(int lock); void scard_unlock(int lock); int scard_enum_devices(uint32 * id, char *optarg); void scardSetInfo(uint32 epoch, uint32 device, uint32 id, uint32 bytes_out); void scard_reset_state(); /* *INDENT-OFF* */ #ifdef __cplusplus } #endif /* *INDENT-ON* */ #endif rdesktop-1.8.3/rdesktop.h0000664000770100510440000001134512216065730014307 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Master include file Copyright (C) Matthew Chapman 1999-2008 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 3 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, see . */ #include #include #include #ifdef _WIN32 #define WINVER 0x0400 #include #include #include #define DIR int #else #include #include #ifdef HAVE_SYS_SELECT_H #include #else #include #include #endif #endif #include /* PATH_MAX */ #ifdef HAVE_SYSEXITS_H #include #endif /* standard exit codes */ #ifndef EX_OK #define EX_OK 0 #endif #ifndef EX_USAGE #define EX_USAGE 64 #endif #ifndef EX_DATAERR #define EX_DATAERR 65 #endif #ifndef EX_NOINPUT #define EX_NOINPUT 66 #endif #ifndef EX_NOUSER #define EX_NOUSER 67 #endif #ifndef EX_NOHOST #define EX_NOHOST 68 #endif #ifndef EX_UNAVAILABLE #define EX_UNAVAILABLE 69 #endif #ifndef EX_SOFTWARE #define EX_SOFTWARE 70 #endif #ifndef EX_OSERR #define EX_OSERR 71 #endif #ifndef EX_OSFILE #define EX_OSFILE 72 #endif #ifndef EX_CANTCREAT #define EX_CANTCREAT 73 #endif #ifndef EX_IOERR #define EX_IOERR 74 #endif #ifndef EX_TEMPFAIL #define EX_TEMPFAIL 75 #endif #ifndef EX_PROTOCOL #define EX_PROTOCOL 76 #endif #ifndef EX_NOPERM #define EX_NOPERM 77 #endif #ifndef EX_CONFIG #define EX_CONFIG 78 #endif /* rdesktop specific exit codes, lined up with disconnect PDU reasons */ #define EXRD_API_DISCONNECT 1 #define EXRD_API_LOGOFF 2 #define EXRD_IDLE_TIMEOUT 3 #define EXRD_LOGON_TIMEOUT 4 #define EXRD_REPLACED 5 #define EXRD_OUT_OF_MEM 6 #define EXRD_DENIED 7 #define EXRD_DENIED_FIPS 8 #define EXRD_INSUFFICIENT_PRIVILEGES 9 #define EXRD_FRESH_CREDENTIALS_REQUIRED 10 #define EXRD_RPC_DISCONNECT_BY_USER 11 #define EXRD_DISCONNECT_BY_USER 12 #define EXRD_LIC_INTERNAL 16 #define EXRD_LIC_NOSERVER 17 #define EXRD_LIC_NOLICENSE 18 #define EXRD_LIC_MSG 19 #define EXRD_LIC_HWID 20 #define EXRD_LIC_CLIENT 21 #define EXRD_LIC_NET 22 #define EXRD_LIC_PROTO 23 #define EXRD_LIC_ENC 24 #define EXRD_LIC_UPGRADE 25 #define EXRD_LIC_NOREMOTE 26 /* other exit codes */ #define EXRD_WINDOW_CLOSED 62 #define EXRD_UNKNOWN 63 #ifdef WITH_DEBUG #define DEBUG(args) printf args; #else #define DEBUG(args) #endif #ifdef WITH_DEBUG_KBD #define DEBUG_KBD(args) printf args; #else #define DEBUG_KBD(args) #endif #ifdef WITH_DEBUG_RDP5 #define DEBUG_RDP5(args) printf args; #else #define DEBUG_RDP5(args) #endif #ifdef WITH_DEBUG_CLIPBOARD #define DEBUG_CLIPBOARD(args) printf args; #else #define DEBUG_CLIPBOARD(args) #endif #ifdef WITH_DEBUG_SOUND #define DEBUG_SOUND(args) printf args; #else #define DEBUG_SOUND(args) #endif #ifdef WITH_DEBUG_CHANNEL #define DEBUG_CHANNEL(args) printf args; #else #define DEBUG_CHANNEL(args) #endif #ifdef WITH_DEBUG_SCARD #define DEBUG_SCARD(args) printf args; #else #define DEBUG_SCARD(args) #endif #define STRNCPY(dst,src,n) { strncpy(dst,src,n-1); dst[n-1] = 0; } #ifndef MIN #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #endif #ifndef MAX #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif /* timeval macros */ #ifndef timerisset #define timerisset(tvp)\ ((tvp)->tv_sec || (tvp)->tv_usec) #endif #ifndef timercmp #define timercmp(tvp, uvp, cmp)\ ((tvp)->tv_sec cmp (uvp)->tv_sec ||\ (tvp)->tv_sec == (uvp)->tv_sec &&\ (tvp)->tv_usec cmp (uvp)->tv_usec) #endif #ifndef timerclear #define timerclear(tvp)\ ((tvp)->tv_sec = (tvp)->tv_usec = 0) #endif /* If configure does not define the endianess, try to find it out */ #if !defined(L_ENDIAN) && !defined(B_ENDIAN) #if __BYTE_ORDER == __LITTLE_ENDIAN #define L_ENDIAN #elif __BYTE_ORDER == __BIG_ENDIAN #define B_ENDIAN #else #error Unknown endianness. Edit rdesktop.h. #endif #endif /* B_ENDIAN, L_ENDIAN from configure */ /* No need for alignment on x86 and amd64 */ #if !defined(NEED_ALIGN) #if !(defined(__x86__) || defined(__x86_64__) || \ defined(__AMD64__) || defined(_M_IX86) || \ defined(__i386__)) #define NEED_ALIGN #endif #endif #include "parse.h" #include "constants.h" #include "types.h" #ifndef MAKE_PROTO #include "proto.h" #endif rdesktop-1.8.3/rdpsnd_dsp.h0000664000770100510440000000242611323031512014601 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Sound DSP routines Copyright (C) Michael Gernoth 2006-2008 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 3 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, see . */ /* Software volume control */ void rdpsnd_dsp_softvol_set(uint16 left, uint16 right); /* Endian conversion */ void rdpsnd_dsp_swapbytes(unsigned char *buffer, unsigned int size, RD_WAVEFORMATEX * format); /* Resample control */ RD_BOOL rdpsnd_dsp_resample_set(uint32 device_srate, uint16 device_bitspersample, uint16 device_channels); RD_BOOL rdpsnd_dsp_resample_supported(RD_WAVEFORMATEX * pwfx); STREAM rdpsnd_dsp_process(unsigned char *data, unsigned int size, struct audio_driver *current_driver, RD_WAVEFORMATEX * format); rdesktop-1.8.3/rdpsnd.h0000664000770100510440000000361411323031512013733 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Sound infrastructure Copyright (C) Michael Gernoth 2006-2008 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 3 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, see . */ struct audio_packet { struct stream s; uint16 tick; uint8 index; struct timeval arrive_tv; struct timeval completion_tv; }; struct audio_driver { void (*add_fds) (int *n, fd_set * rfds, fd_set * wfds, struct timeval * tv); void (*check_fds) (fd_set * rfds, fd_set * wfds); RD_BOOL(*wave_out_open) (void); void (*wave_out_close) (void); RD_BOOL(*wave_out_format_supported) (RD_WAVEFORMATEX * pwfx); RD_BOOL(*wave_out_set_format) (RD_WAVEFORMATEX * pwfx); void (*wave_out_volume) (uint16 left, uint16 right); RD_BOOL(*wave_in_open) (void); void (*wave_in_close) (void); RD_BOOL(*wave_in_format_supported) (RD_WAVEFORMATEX * pwfx); RD_BOOL(*wave_in_set_format) (RD_WAVEFORMATEX * pwfx); void (*wave_in_volume) (uint16 left, uint16 right); char *name; char *description; int need_byteswap_on_be; int need_resampling; struct audio_driver *next; }; /* Driver register functions */ struct audio_driver *alsa_register(char *options); struct audio_driver *libao_register(char *options); struct audio_driver *oss_register(char *options); struct audio_driver *sgi_register(char *options); struct audio_driver *sun_register(char *options); rdesktop-1.8.3/scancodes.h0000664000770100510440000002263507747360213014431 0ustar hean01hean01 /* Two defines for every scancode: One called SCANCODE_KEY_, where is the key location number. One called SCANCODE_CHAR_, where is the unshifted character on a US 101/102 keyboard. See the Microsoft document "Keyboard Scan Code Specification" for more information. Up keys normally have scancode values +0x80. 0x0: Avoid 0x1- 0x59: Normal 0x60, 0x61: Avoid, since the up key would be 0xe1, 0xe1 0x61 - 0x79: Normal 0xfa - : keyboard drivers interpret these as responses from the 8042 chip We use bit 7 to indicate 0xe0 prefix instead of two-byte sequence (0xe0, something). Eq., 0xe 0x38 is defined as (0x80 | 0x38) */ /* FIXME: Special keys like Numeric / are very complicated and emits many scancodes. */ #define SCANCODE_EXTENDED 0x80 #define SCANCODE_KEY_1 0x29 #define SCANCODE_CHAR_GRAVE 0x29 #define SCANCODE_KEY_2 0x2 #define SCANCODE_CHAR_1 SCANCODE_KEY_2 #define SCANCODE_KEY_3 0x3 #define SCANCODE_CHAR_2 SCANCODE_KEY_3 #define SCANCODE_KEY_4 0x4 #define SCANCODE_CHAR_3 SCANCODE_KEY_4 #define SCANCODE_KEY_5 0x5 #define SCANCODE_CHAR_4 SCANCODE_KEY_5 #define SCANCODE_KEY_6 0x6 #define SCANCODE_CHAR_5 SCANCODE_KEY_6 #define SCANCODE_KEY_7 0x7 #define SCANCODE_CHAR_6 SCANCODE_KEY_7 #define SCANCODE_KEY_8 0x8 #define SCANCODE_CHAR_7 SCANCODE_KEY_8 #define SCANCODE_KEY_9 0x9 #define SCANCODE_CHAR_8 SCANCODE_KEY_9 #define SCANCODE_KEY_10 0xa #define SCANCODE_CHAR_9 SCANCODE_KEY_10 #define SCANCODE_KEY_11 0xb #define SCANCODE_CHAR_0 SCANCODE_KEY_11 #define SCANCODE_KEY_12 0xc #define SCANCODE_CHAR_MINUS SCANCODE_KEY_12 #define SCANCODE_KEY_13 0xd #define SCANCODE_CHAR_EQUAL SCANCODE_KEY_13 /* Key 14 does not exist */ #define SCANCODE_KEY_15 0xe #define SCANCODE_CHAR_BACKSPACE SCANCODE_KEY_15 #define SCANCODE_KEY_16 0xf #define SCANCODE_CHAR_TAB SCANCODE_KEY_16 #define SCANCODE_KEY_17 0x10 #define SCANCODE_CHAR_Q SCANCODE_KEY_17 #define SCANCODE_KEY_18 0x11 #define SCANCODE_CHAR_W SCANCODE_KEY_18 #define SCANCODE_KEY_19 0x12 #define SCANCODE_CHAR_E SCANCODE_KEY_19 #define SCANCODE_KEY_20 0x13 #define SCANCODE_CHAR_R SCANCODE_KEY_20 #define SCANCODE_KEY_21 0x14 #define SCANCODE_CHAR_T SCANCODE_KEY_21 #define SCANCODE_KEY_22 0x15 #define SCANCODE_CHAR_Y SCANCODE_KEY_22 #define SCANCODE_KEY_23 0x16 #define SCANCODE_CHAR_U SCANCODE_KEY_23 #define SCANCODE_KEY_24 0x17 #define SCANCODE_CHAR_I SCANCODE_KEY_24 #define SCANCODE_KEY_25 0x18 #define SCANCODE_CHAR_O SCANCODE_KEY_25 #define SCANCODE_KEY_26 0x19 #define SCANCODE_CHAR_P SCANCODE_KEY_26 #define SCANCODE_KEY_27 0x1a #define SCANCODE_CHAR_BRACKETLEFT SCANCODE_KEY_27 #define SCANCODE_KEY_28 0x1b #define SCANCODE_CHAR_BRACKETRIGHT SCANCODE_KEY_28 /* Only on US keyboard */ #define SCANCODE_KEY_29 0x2b #define SCANCODE_CHAR_BACKSLASH SCANCODE_KEY_29 #define SCANCODE_KEY_30 0x3a #define SCANCODE_CHAR_CAPSLOCK SCANCODE_KEY_30 #define SCANCODE_KEY_31 0x1e #define SCANCODE_CHAR_A SCANCODE_KEY_31 #define SCANCODE_KEY_32 0x1f #define SCANCODE_CHAR_S SCANCODE_KEY_32 #define SCANCODE_KEY_33 0x20 #define SCANCODE_CHAR_D SCANCODE_KEY_33 #define SCANCODE_KEY_34 0x21 #define SCANCODE_CHAR_F SCANCODE_KEY_34 #define SCANCODE_KEY_35 0x22 #define SCANCODE_CHAR_G SCANCODE_KEY_35 #define SCANCODE_KEY_36 0x23 #define SCANCODE_CHAR_H SCANCODE_KEY_36 #define SCANCODE_KEY_37 0x24 #define SCANCODE_CHAR_J SCANCODE_KEY_37 #define SCANCODE_KEY_38 0x25 #define SCANCODE_CHAR_K SCANCODE_KEY_38 #define SCANCODE_KEY_39 0x26 #define SCANCODE_CHAR_L SCANCODE_KEY_39 #define SCANCODE_KEY_40 0x27 #define SCANCODE_CHAR_SEMICOLON SCANCODE_KEY_40 #define SCANCODE_KEY_41 0x28 #define SCANCODE_CHAR_APOSTROPHE SCANCODE_KEY_41 /* Only on international keyboard */ #define SCANCODE_KEY_42 0x2b #define SCANCODE_KEY_43 0x1c #define SCANCODE_CHAR_ENTER SCANCODE_KEY_43 #define SCANCODE_KEY_44 0x2a #define SCANCODE_CHAR_LSHIFT SCANCODE_KEY_44 /* Only on international keyboard */ #define SCANCODE_KEY_45 0x56 #define SCANCODE_KEY_46 0x2c #define SCANCODE_CHAR_Z SCANCODE_KEY_46 #define SCANCODE_KEY_47 0x2d #define SCANCODE_CHAR_X SCANCODE_KEY_47 #define SCANCODE_KEY_48 0x2e #define SCANCODE_CHAR_C SCANCODE_KEY_48 #define SCANCODE_KEY_49 0x2f #define SCANCODE_CHAR_V SCANCODE_KEY_49 #define SCANCODE_KEY_50 0x30 #define SCANCODE_CHAR_B SCANCODE_KEY_50 #define SCANCODE_KEY_51 0x31 #define SCANCODE_CHAR_N SCANCODE_KEY_51 #define SCANCODE_KEY_52 0x32 #define SCANCODE_CHAR_M SCANCODE_KEY_52 #define SCANCODE_KEY_53 0x33 #define SCANCODE_CHAR_COMMA SCANCODE_KEY_53 #define SCANCODE_KEY_54 0x34 #define SCANCODE_CHAR_DOT SCANCODE_KEY_54 #define SCANCODE_KEY_55 0x35 #define SCANCODE_CHAR_SLASH SCANCODE_KEY_55 /* Only on Brazilian and some Far East keyboards */ #define SCANCODE_KEY_56 0x73 #define SCANCODE_KEY_57 0x36 #define SCANCODE_CHAR_RSHIFT SCANCODE_KEY_57 #define SCANCODE_KEY_58 0x1d #define SCANCODE_CHAR_LCTRL SCANCODE_KEY_58 /* Key 59 does not exist */ #define SCANCODE_KEY_60 0x38 #define SCANCODE_CHAR_LALT SCANCODE_KEY_60 #define SCANCODE_KEY_61 0x39 #define SCANCODE_CHAR_SPACE SCANCODE_KEY_61 #define SCANCODE_KEY_62 (SCANCODE_EXTENDED | 0x38) #define SCANCODE_CHAR_RALT SCANCODE_KEY_62 /* Key 63 does not exist */ #define SCANCODE_KEY_64 (SCANCODE_EXTENDED | 0x1d) #define SCANCODE_CHAR_RCTRL SCANCODE_KEY_64 /* Key 65 - 74 does not exist */ #define SCANCODE_KEY_75 (SCANCODE_EXTENDED | 0x52) #define SCANCODE_CHAR_INSERT SCANCODE_KEY_75 #define SCANCODE_KEY_76 (SCANCODE_EXTENDED | 0x53) #define SCANCODE_CHAR_DELETE SCANCODE_KEY_76 /* Key 77 - 78 does not exist */ #define SCANCODE_KEY_79 (SCANCODE_EXTENDED | 0x4b) #define SCANCODE_CHAR_LARROW SCANCODE_KEY_79 #define SCANCODE_KEY_80 (SCANCODE_EXTENDED | 0x47) #define SCANCODE_CHAR_HOME SCANCODE_KEY_80 #define SCANCODE_KEY_81 (SCANCODE_EXTENDED | 0x4f) #define SCANCODE_CHAR_END SCANCODE_KEY_81 /* Key 82 does not exist */ #define SCANCODE_KEY_83 (SCANCODE_EXTENDED | 0x48) #define SCANCODE_CHAR_UPARROW SCANCODE_KEY_83 #define SCANCODE_KEY_84 (SCANCODE_EXTENDED | 0x50) #define SCANCODE_CHAR_DNARROW SCANCODE_KEY_84 #define SCANCODE_KEY_85 (SCANCODE_EXTENDED | 0x49) #define SCANCODE_CHAR_PAGEUP SCANCODE_KEY_85 #define SCANCODE_KEY_86 (SCANCODE_EXTENDED | 0x51) #define SCANCODE_CHAR_PAGEDOWN SCANCODE_KEY_86 /* Key 87 - 88 does not exist */ #define SCANCODE_KEY_89 (SCANCODE_EXTENDED | 0x4d) #define SCANCODE_CHAR_RARROW SCANCODE_KEY_89 #define SCANCODE_KEY_90 0x45 #define SCANCODE_CHAR_NUMLOCK SCANCODE_KEY_90 #define SCANCODE_KEY_91 0x47 #define SCANCODE_CHAR_NUMERIC7 SCANCODE_KEY_91 #define SCANCODE_KEY_92 0x4b #define SCANCODE_CHAR_NUMERIC4 SCANCODE_KEY_92 #define SCANCODE_KEY_93 0x4f #define SCANCODE_CHAR_NUMERIC1 SCANCODE_KEY_93 /* Key 94 does not exist */ #define SCANCODE_KEY_95 (SCANCODE_EXTENDED | 0x35) #define SCANCODE_CHAR_NUMERICSLASH SCANCODE_KEY_95 #define SCANCODE_KEY_96 0x48 #define SCANCODE_CHAR_NUMERIC8 SCANCODE_KEY_96 #define SCANCODE_KEY_97 0x4c #define SCANCODE_CHAR_NUMERIC5 SCANCODE_KEY_97 #define SCANCODE_KEY_98 0x50 #define SCANCODE_CHAR_NUMERIC2 SCANCODE_KEY_98 #define SCANCODE_KEY_99 0x52 #define SCANCODE_CHAR_NUMERIC0 SCANCODE_KEY_99 #define SCANCODE_KEY_100 0x37 #define SCANCODE_CHAR_NUMERICSTAR SCANCODE_KEY_100 #define SCANCODE_KEY_101 0x49 #define SCANCODE_CHAR_NUMERIC9 SCANCODE_KEY_101 #define SCANCODE_KEY_102 0x4d #define SCANCODE_CHAR_NUMERIC6 SCANCODE_KEY_102 #define SCANCODE_KEY_103 0x51 #define SCANCODE_CHAR_NUMERIC3 SCANCODE_KEY_103 #define SCANCODE_KEY_104 0x53 #define SCANCODE_CHAR_NUMERICDOT SCANCODE_KEY_104 #define SCANCODE_KEY_105 0x4a #define SCANCODE_CHAR_NUMERICMINUS SCANCODE_KEY_105 #define SCANCODE_KEY_106 0x4e #define SCANCODE_CHAR_NUMERICPLUS SCANCODE_KEY_106 /* Only on Brazilian and some Far East keyboards */ #define SCANCODE_KEY_107 0x #define SCANCODE_KEY_108 (SCANCODE_EXTENDED | 0x1c) #define SCANCODE_CHAR_NUMERICENTER SCANCODE_KEY_108 /* Key 109 does not exist */ #define SCANCODE_KEY_110 0x1 #define SCANCODE_CHAR_ESC SCANCODE_KEY_110 /* Key 111 does not exist */ #define SCANCODE_KEY_112 0x3b #define SCANCODE_CHAR_F1 SCANCODE_KEY_112 #define SCANCODE_KEY_113 0x3c #define SCANCODE_CHAR_F2 SCANCODE_KEY_113 #define SCANCODE_KEY_114 0x3d #define SCANCODE_CHAR_F3 SCANCODE_KEY_114 #define SCANCODE_KEY_115 0x3e #define SCANCODE_CHAR_F4 SCANCODE_KEY_115 #define SCANCODE_KEY_116 0x3f #define SCANCODE_CHAR_F5 SCANCODE_KEY_116 #define SCANCODE_KEY_117 0x40 #define SCANCODE_CHAR_F6 SCANCODE_KEY_117 #define SCANCODE_KEY_118 0x41 #define SCANCODE_CHAR_F7 SCANCODE_KEY_118 #define SCANCODE_KEY_119 0x42 #define SCANCODE_CHAR_F8 SCANCODE_KEY_119 #define SCANCODE_KEY_120 0x43 #define SCANCODE_CHAR_F9 SCANCODE_KEY_120 #define SCANCODE_KEY_121 0x44 #define SCANCODE_CHAR_F10 SCANCODE_KEY_121 #define SCANCODE_KEY_122 0x57 #define SCANCODE_CHAR_F11 SCANCODE_KEY_122 #define SCANCODE_KEY_123 0x58 #define SCANCODE_CHAR_F12 SCANCODE_KEY_123 /* Key 124: The Print Screen sequence is complicated, and hardcoded in xkeymap.c */ #define SCANCODE_KEY_125 0x46 #define SCANCODE_CHAR_SCROLLLOCK SCANCODE_KEY_125 /* Key 126: The Pause and Break sequences is complicated, and hardcoded in xkeymap.c */ /* The keys below does not have any key location number */ #define SCANCODE_CHAR_LWIN (SCANCODE_EXTENDED | 0x5b) #define SCANCODE_CHAR_RWIN (SCANCODE_EXTENDED | 0x5c) #define SCANCODE_CHAR_APPLICATION (SCANCODE_EXTENDED | 0x5d) #define SCANCODE_CHAR_ACPIPOWER (SCANCODE_EXTENDED | 0x5e) #define SCANCODE_CHAR_ACPISLEEP (SCANCODE_EXTENDED | 0x5f) #define SCANCODE_CHAR_ACPIWAKE (SCANCODE_EXTENDED | 0x63) rdesktop-1.8.3/scard.h0000664000770100510440000001364312404306606013552 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Smart Card support Copyright (C) Alexi Volkov 2006 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 3 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, see . */ #include #include "proto.h" /*************************************************************************/ /* these are the additional types needed to split out 64-vs-32-bit APIs */ /* */ /* The point of all of this is to avoid patching the existing smartcard * infrastructure (PC/SC Lite, libmusclecard+libmusclepkcs11 or CoolKey, any * other apps linking against any of these) because the need for patches * spreads without limit. The alternative is to patch the heck out of rdesktop, * which is already being done anyway. * * - jared.jennings@eglin.af.mil, 2 Aug 2006 */ #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif /* A DWORD when dealing with the smartcard stuff. Could be 32 bits or 64. */ typedef DWORD MYPCSC_DWORD; /* A DWORD when talking to the server. Must be exactly 32 bits all the time.*/ typedef uint32_t SERVER_DWORD; typedef SCARDCONTEXT MYPCSC_SCARDCONTEXT; typedef SCARDHANDLE MYPCSC_SCARDHANDLE; typedef uint32_t SERVER_SCARDCONTEXT; typedef uint32_t SERVER_SCARDHANDLE; typedef SCARD_READERSTATE MYPCSC_SCARD_READERSTATE_A, *MYPCSC_LPSCARD_READERSTATE_A; typedef struct { const char *szReader; void *pvUserData; SERVER_DWORD dwCurrentState; SERVER_DWORD dwEventState; SERVER_DWORD cbAtr; unsigned char rgbAtr[36]; } SERVER_SCARD_READERSTATE_A; typedef SERVER_SCARD_READERSTATE_A *SERVER_LPSCARD_READERSTATE_A; #define SERVER_SCARDSTATESIZE (sizeof(SERVER_SCARD_READERSTATE_A) - sizeof(const char *) - sizeof(void *)) #define MYPCSC_SCARDSTATESIZE (sizeof(MYPCSC_SCARD_READERSTATE_A) - sizeof(const char *) - sizeof(void *)) typedef struct _SERVER_SCARD_IO_REQUEST { SERVER_DWORD dwProtocol; /* Protocol identifier */ SERVER_DWORD cbPciLength; /* Protocol Control Inf Length */ } SERVER_SCARD_IO_REQUEST, *SERVER_LPSCARD_IO_REQUEST; typedef SCARD_IO_REQUEST MYPCSC_SCARD_IO_REQUEST; typedef LPSCARD_IO_REQUEST MYPCSC_LPSCARD_IO_REQUEST; /* */ /* */ /*************************************************************************/ #define SC_TRUE 1 #define SC_FALSE 0 #define SC_ESTABLISH_CONTEXT 0x00090014 /* EstablishContext */ #define SC_RELEASE_CONTEXT 0x00090018 /* ReleaseContext */ #define SC_IS_VALID_CONTEXT 0x0009001C /* IsValidContext */ #define SC_LIST_READER_GROUPS 0x00090020 /* ListReaderGroups */ #define SC_LIST_READERS 0x00090028 /* ListReadersA */ #define SC_INTRODUCE_READER_GROUP 0x00090050 /* IntroduceReaderGroup */ #define SC_FORGET_READER_GROUP 0x00090058 /* ForgetReader */ #define SC_INTRODUCE_READER 0x00090060 /* IntroduceReader */ #define SC_FORGET_READER 0x00090068 /* IntroduceReader */ #define SC_ADD_READER_TO_GROUP 0x00090070 /* AddReaderToGroup */ #define SC_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup */ #define SC_CONNECT 0x000900AC /* ConnectA */ #define SC_RECONNECT 0x000900B4 /* Reconnect */ #define SC_DISCONNECT 0x000900B8 /* Disconnect */ #define SC_GET_STATUS_CHANGE 0x000900A0 /* GetStatusChangeA */ #define SC_CANCEL 0x000900A8 /* Cancel */ #define SC_BEGIN_TRANSACTION 0x000900BC /* BeginTransaction */ #define SC_END_TRANSACTION 0x000900C0 /* EndTransaction */ #define SC_STATE 0x000900C4 /* State */ #define SC_STATUS 0x000900C8 /* StatusA */ #define SC_TRANSMIT 0x000900D0 /* Transmit */ #define SC_CONTROL 0x000900D4 /* Control */ #define SC_GETATTRIB 0x000900D8 /* GetAttrib */ #define SC_SETATTRIB 0x000900DC /* SetAttrib */ #define SC_ACCESS_STARTED_EVENT 0x000900E0 /* SCardAccessStartedEvent */ #define SC_LOCATE_CARDS_BY_ATR 0x000900E8 /* LocateCardsByATR */ /* #define INPUT_LINKED 0x00020000 */ #define INPUT_LINKED 0xFFFFFFFF #define SC_THREAD_FUNCTION(f) void *(*f)(void *) extern RDPDR_DEVICE g_rdpdr_device[]; typedef struct _MEM_HANDLE { struct _MEM_HANDLE *prevHandle; struct _MEM_HANDLE *nextHandle; int dataSize; } MEM_HANDLE, *PMEM_HANDLE; typedef struct _SCARD_ATRMASK_L { unsigned int cbAtr; unsigned char rgbAtr[36]; unsigned char rgbMask[36]; } SCARD_ATRMASK_L, *PSCARD_ATRMASK_L, *LPSCARD_ATRMASK_L; typedef struct _TSCNameMapRec { char alias[128]; char name[128]; char vendor[128]; } TSCNameMapRec, *PSCNameMapRec; typedef struct _TSCHCardRec { DWORD hCard; char *vendor; struct _TSCHCardRec *next; struct _TSCHCardRec *prev; } TSCHCardRec, *PSCHCardRec; typedef struct _TSCThreadData { uint32 device; uint32 id; uint32 epoch; RD_NTHANDLE handle; uint32 request; STREAM in; STREAM out; PMEM_HANDLE memHandle; struct _TSCThreadData *next; } TSCThreadData, *PSCThreadData; typedef struct _TThreadListElement { pthread_t thread; pthread_mutex_t busy; pthread_cond_t nodata; PSCThreadData data; struct _TThreadListElement *next; } TThreadListElement, *PThreadListElement; rdesktop-1.8.3/seamless.h0000664000770100510440000000143311640565273014274 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Seamless Windows support Copyright 2005-2008 Peter Astrand for Cendio AB 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 3 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, see . */ rdesktop-1.8.3/ssl.h0000664000770100510440000000507312041500663013251 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Secure sockets abstraction layer Copyright (C) Matthew Chapman 1999-2008 Copyright (C) Jay Sorg 2006-2008 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 3 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, see . */ #ifndef _RDSSL_H #define _RDSSL_H #include #include #include #include #include #include #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090800f) #define D2I_X509_CONST const #else #define D2I_X509_CONST #endif #define RDSSL_RC4 RC4_KEY #define RDSSL_SHA1 SHA_CTX #define RDSSL_MD5 MD5_CTX #define RDSSL_CERT X509 #define RDSSL_RKEY RSA void rdssl_sha1_init(RDSSL_SHA1 * sha1); void rdssl_sha1_update(RDSSL_SHA1 * sha1, uint8 * data, uint32 len); void rdssl_sha1_final(RDSSL_SHA1 * sha1, uint8 * out_data); void rdssl_md5_init(RDSSL_MD5 * md5); void rdssl_md5_update(RDSSL_MD5 * md5, uint8 * data, uint32 len); void rdssl_md5_final(RDSSL_MD5 * md5, uint8 * out_data); void rdssl_rc4_set_key(RDSSL_RC4 * rc4, uint8 * key, uint32 len); void rdssl_rc4_crypt(RDSSL_RC4 * rc4, uint8 * in_data, uint8 * out_data, uint32 len); void rdssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, uint8 * exponent); RDSSL_CERT *rdssl_cert_read(uint8 * data, uint32 len); void rdssl_cert_free(RDSSL_CERT * cert); RDSSL_RKEY *rdssl_cert_to_rkey(RDSSL_CERT * cert, uint32 * key_len); RD_BOOL rdssl_certs_ok(RDSSL_CERT * server_cert, RDSSL_CERT * cacert); int rdssl_cert_print_fp(FILE * fp, RDSSL_CERT * cert); void rdssl_rkey_free(RDSSL_RKEY * rkey); int rdssl_rkey_get_exp_mod(RDSSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus, uint32 max_mod_len); RD_BOOL rdssl_sig_ok(uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len, uint8 * signature, uint32 sig_len); void rdssl_hmac_md5(const void *key, int key_len, const unsigned char *msg, int msg_len, unsigned char *md); #endif rdesktop-1.8.3/types.h0000664000770100510440000001306312336630667013631 0ustar hean01hean01/* rdesktop: A Remote Desktop Protocol client. Common data types Copyright (C) Matthew Chapman 1999-2008 Copyright 2014 Henrik Andersson for Cendio AB 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 3 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, see . */ typedef int RD_BOOL; #ifndef True #define True (1) #define False (0) #endif typedef unsigned char uint8; typedef signed char sint8; typedef unsigned short uint16; typedef signed short sint16; typedef unsigned int uint32; typedef signed int sint32; typedef void *RD_HBITMAP; typedef void *RD_HGLYPH; typedef void *RD_HCOLOURMAP; typedef void *RD_HCURSOR; typedef enum _RDP_VERSION { RDP_V4 = 4, RDP_V5 = 5, RDP_V6 = 6 } RDP_VERSION; typedef struct _RD_POINT { sint16 x, y; } RD_POINT; typedef struct _COLOURENTRY { uint8 red; uint8 green; uint8 blue; } COLOURENTRY; typedef struct _COLOURMAP { uint16 ncolours; COLOURENTRY *colours; } COLOURMAP; typedef struct _BOUNDS { sint16 left; sint16 top; sint16 right; sint16 bottom; } BOUNDS; typedef struct _PEN { uint8 style; uint8 width; uint32 colour; } PEN; /* this is whats in the brush cache */ typedef struct _BRUSHDATA { uint32 colour_code; uint32 data_size; uint8 *data; } BRUSHDATA; typedef struct _BRUSH { uint8 xorigin; uint8 yorigin; uint8 style; uint8 pattern[8]; BRUSHDATA *bd; } BRUSH; typedef struct _FONTGLYPH { sint16 offset; sint16 baseline; uint16 width; uint16 height; RD_HBITMAP pixmap; } FONTGLYPH; typedef struct _DATABLOB { void *data; int size; } DATABLOB; typedef struct _key_translation { /* For normal scancode translations */ uint8 scancode; uint16 modifiers; /* For sequences. If keysym is nonzero, the fields above are not used. */ uint32 seq_keysym; /* Really KeySym */ struct _key_translation *next; } key_translation; typedef struct _key_translation_entry { key_translation *tr; /* The full KeySym for this entry, not KEYMAP_MASKed */ uint32 keysym; /* This will be non-NULL if there has been a hash collision */ struct _key_translation_entry *next; } key_translation_entry; typedef struct _VCHANNEL { uint16 mcs_id; char name[8]; uint32 flags; struct stream in; void (*process) (STREAM); } VCHANNEL; /* PSTCACHE */ typedef uint8 HASH_KEY[8]; /* Header for an entry in the persistent bitmap cache file */ typedef struct _PSTCACHE_CELLHEADER { HASH_KEY key; uint8 width, height; uint16 length; uint32 stamp; } CELLHEADER; #define MAX_CBSIZE 256 /* RDPSND */ typedef struct _RD_WAVEFORMATEX { uint16 wFormatTag; uint16 nChannels; uint32 nSamplesPerSec; uint32 nAvgBytesPerSec; uint16 nBlockAlign; uint16 wBitsPerSample; uint16 cbSize; uint8 cb[MAX_CBSIZE]; } RD_WAVEFORMATEX; typedef struct _RDPCOMP { uint32 roff; uint8 hist[RDP_MPPC_DICT_SIZE]; struct stream ns; } RDPCOMP; /* RDPDR */ typedef uint32 RD_NTSTATUS; typedef uint32 RD_NTHANDLE; typedef struct _DEVICE_FNS { RD_NTSTATUS(*create) (uint32 device, uint32 desired_access, uint32 share_mode, uint32 create_disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * handle); RD_NTSTATUS(*close) (RD_NTHANDLE handle); RD_NTSTATUS(*read) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result); RD_NTSTATUS(*write) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result); RD_NTSTATUS(*device_control) (RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out); } DEVICE_FNS; typedef struct rdpdr_device_info { uint32 device_type; RD_NTHANDLE handle; char name[8]; char *local_path; void *pdevice_data; } RDPDR_DEVICE; typedef struct rdpdr_serial_device_info { int dtr; int rts; uint32 control, xonoff, onlimit, offlimit; uint32 baud_rate, queue_in_size, queue_out_size, wait_mask, read_interval_timeout, read_total_timeout_multiplier, read_total_timeout_constant, write_total_timeout_multiplier, write_total_timeout_constant, posix_wait_mask; uint8 stop_bits, parity, word_length; uint8 chars[6]; struct termios *ptermios, *pold_termios; int event_txempty, event_cts, event_dsr, event_rlsd, event_pending; } SERIAL_DEVICE; typedef struct rdpdr_parallel_device_info { char *driver, *printer; uint32 queue_in_size, queue_out_size, wait_mask, read_interval_timeout, read_total_timeout_multiplier, read_total_timeout_constant, write_total_timeout_multiplier, write_total_timeout_constant, posix_wait_mask, bloblen; uint8 *blob; } PARALLEL_DEVICE; typedef struct rdpdr_printer_info { FILE *printer_fp; char *driver, *printer; uint32 bloblen; uint8 *blob; RD_BOOL default_printer; } PRINTER; typedef struct notify_data { time_t modify_time; time_t status_time; time_t total_time; unsigned int num_entries; } NOTIFY; #ifndef PATH_MAX #define PATH_MAX 256 #endif typedef struct fileinfo { uint32 device_id, flags_and_attributes, accessmask; char path[PATH_MAX]; DIR *pdir; struct dirent *pdirent; char pattern[PATH_MAX]; RD_BOOL delete_on_close; NOTIFY notify; uint32 info_class; } FILEINFO; typedef RD_BOOL(*str_handle_lines_t) (const char *line, void *data); rdesktop-1.8.3/xproto.h0000664000770100510440000000156312216606214014006 0ustar hean01hean01void xclip_handle_SelectionNotify(XSelectionEvent * event); void xclip_handle_SelectionRequest(XSelectionRequestEvent * xevent); void xclip_handle_SelectionClear(void); void xclip_handle_PropertyNotify(XPropertyEvent * xev); int ewmh_get_window_state(Window w); int ewmh_change_state(Window wnd, int state); int ewmh_move_to_desktop(Window wnd, unsigned int desktop); int ewmh_get_window_desktop(Window wnd); void ewmh_set_wm_name(Window wnd, const char *title); int ewmh_set_window_popup(Window wnd); int ewmh_set_window_modal(Window wnd); void ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data); void ewmh_del_icon(Window wnd, int width, int height); int ewmh_set_window_above(Window wnd); RD_BOOL ewmh_is_window_above(Window w); void set_keypress_keysym(unsigned int keycode, KeySym keysym); KeySym reset_keypress_keysym(unsigned int keycode, KeySym keysym); rdesktop-1.8.3/proto.head0000664000770100510440000000157511323031512014262 0ustar hean01hean01/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Copyright (C) Matthew Chapman 1999-2007 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 3 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, see . */ #ifndef RDESKTOP_PROTO_H #define RDESKTOP_PROTO_H /* *INDENT-OFF* */ #ifdef __cplusplus extern "C" { #endif /* *INDENT-ON* */ rdesktop-1.8.3/proto.tail0000664000770100510440000000011210303426601014300 0ustar hean01hean01 /* *INDENT-OFF* */ #ifdef __cplusplus } #endif /* *INDENT-ON* */ #endif rdesktop-1.8.3/keymaps/ar0000664000770100510440000000427707554011737014316 0ustar hean01hean01# generated from XKB map ar include common map 0x401 exclam 0x02 shift at 0x03 shift numbersign 0x04 shift dollar 0x05 shift percent 0x06 shift asciicircum 0x07 shift ampersand 0x08 shift asterisk 0x09 shift parenleft 0x0a shift parenright 0x0b shift minus 0x0c underscore 0x0c shift equal 0x0d plus 0x0d shift Arabic_dad 0x10 altgr Arabic_fatha 0x10 shift altgr Arabic_sad 0x11 altgr Arabic_fathatan 0x11 shift altgr Arabic_theh 0x12 altgr Arabic_damma 0x12 shift altgr Arabic_qaf 0x13 altgr Arabic_dammatan 0x13 shift altgr Arabic_feh 0x14 altgr UFEF9 0x14 shift altgr Arabic_ghain 0x15 altgr Arabic_hamzaunderalef 0x15 shift altgr Arabic_ain 0x16 altgr grave 0x16 shift altgr Arabic_ha 0x17 altgr division 0x17 shift altgr Arabic_khah 0x18 altgr multiply 0x18 shift altgr Arabic_hah 0x19 altgr Arabic_semicolon 0x19 shift altgr bracketleft 0x1a braceleft 0x1a shift Arabic_jeem 0x1a altgr bracketright 0x1b braceright 0x1b shift Arabic_dal 0x1b altgr Arabic_sheen 0x1e altgr backslash 0x1e shift altgr Arabic_seen 0x1f altgr Arabic_yeh 0x20 altgr bracketleft 0x20 shift altgr Arabic_beh 0x21 altgr bracketright 0x21 shift altgr Arabic_lam 0x22 altgr UFEF7 0x22 shift altgr Arabic_alef 0x23 altgr Arabic_hamzaonalef 0x23 shift altgr Arabic_teh 0x24 altgr Arabic_tatweel 0x24 shift altgr Arabic_noon 0x25 altgr Arabic_comma 0x25 shift altgr Arabic_meem 0x26 altgr slash 0x26 shift altgr semicolon 0x27 colon 0x27 shift Arabic_kaf 0x27 altgr apostrophe 0x28 quotedbl 0x28 shift Arabic_tah 0x28 altgr grave 0x29 asciitilde 0x29 shift Arabic_thal 0x29 altgr Arabic_shadda 0x29 shift altgr backslash 0x2b bar 0x2b shift less 0x2b altgr greater 0x2b shift altgr Arabic_hamzaonyeh 0x2c altgr asciitilde 0x2c shift altgr Arabic_hamza 0x2d altgr Arabic_sukun 0x2d shift altgr Arabic_hamzaonwaw 0x2e altgr Arabic_kasra 0x2e shift altgr Arabic_ra 0x2f altgr Arabic_kasratan 0x2f shift altgr UFEFB 0x30 altgr UFEF5 0x30 shift altgr Arabic_alefmaksura 0x31 altgr Arabic_maddaonalef 0x31 shift altgr Arabic_tehmarbuta 0x32 altgr apostrophe 0x32 shift altgr comma 0x33 less 0x33 shift Arabic_waw 0x33 altgr period 0x34 greater 0x34 shift Arabic_zain 0x34 altgr slash 0x35 question 0x35 shift Arabic_zah 0x35 altgr Arabic_question_mark 0x35 shift altgr rdesktop-1.8.3/keymaps/cs0000664000770100510440000000605012243647767014321 0ustar hean01hean01#Czech keymap #2007-05-28 by Jaroslav Jiricka include common #Additional sequences #2007-05-28 by Jaroslav Jiricka sequence ecaron dead_caron e sequence Ecaron dead_caron E sequence eogonek dead_ogonek e sequence Eogonek dead_ogonek E sequence rcaron dead_caron r sequence Rcaron dead_caron R sequence racute dead_acute r sequence Racute dead_acute R sequence tcaron dead_caron t sequence Tcaron dead_caron T sequence tcedilla dead_cedilla t sequence Tcedilla dead_cedilla T sequence zcaron dead_caron z sequence Zcaron dead_caron Z sequence zacute dead_acute z sequence Zacute dead_acute Z sequence zabovedot dead_abovedot z sequence Zabovedot dead_abovedot Z sequence uring dead_abovering u sequence Uring dead_abovering U sequence udoubleacute dead_doubleacute u sequence Udoubleacute dead_doubleacute U sequence odoubleacute dead_doubleacute o sequence Odoubleacute dead_doubleacute O sequence aogonek dead_ogonek a sequence Aogonek dead_ogonek A sequence abreve dead_breve a sequence Abreve dead_breve A sequence scaron dead_caron s sequence Scaron dead_caron S sequence sacute dead_acute s sequence Sacute dead_acute S sequence scedilla dead_cedilla s sequence Scedilla dead_cedilla S sequence dcaron dead_caron d sequence Dcaron dead_caron D sequence gbreve dead_breve g sequence Gbreve dead_breve G sequence lcaron dead_caron l sequence Lcaron dead_caron L sequence lacute dead_acute l sequence Lacute dead_acute L sequence ccaron dead_caron c sequence Ccaron dead_caron C sequence ncaron dead_caron n sequence Ncaron dead_caron N sequence nacute dead_acute n sequence Nacute dead_acute N #Additional sequences end map 0x405 semicolon 0x29 dead_abovering 0x29 shift plus 0x02 1 0x02 shift dead_tilde 0x02 altgr asciitilde 0x02 altgr ecaron 0x03 2 0x03 shift dead_caron 0x03 altgr scaron 0x04 3 0x04 shift dead_circumflex 0x04 altgr ccaron 0x05 4 0x05 shift dead_breve 0x05 altgr rcaron 0x06 5 0x06 shift dead_abovering 0x06 altgr zcaron 0x07 6 0x07 shift dead_ogonek 0x07 altgr yacute 0x08 7 0x08 shift dead_grave 0x08 altgr aacute 0x09 8 0x09 shift dead_abovedot 0x08 altgr iacute 0x0a 9 0x0a shift dead_acute 0x08 altgr eacute 0x0b 0 0x0b shift dead_doubleacute 0x0b altgr equal 0x0c percent 0x0c shift dead_macron 0x0c altgr dead_acute 0x0d dead_caron 0x0d shift dead_cedilla 0x0d altgr backslash 0x10 altgr bar 0x11 altgr EuroSign 0x12 altgr z 0x15 addupper uacute 0x1a slash 0x1a shift division 0x1a altgr parenright 0x1b parenleft 0x1b shift multiply 0x1b altgr dead_diaeresis 0x2b apostrophe 0x2b shift currency 0x2b altgr dstroke 0x1f altgr Dstroke 0x20 altgr bracketleft 0x21 altgr bracketright 0x22 altgr lstroke 0x25 altgr Lstroke 0x26 altgr uring 0x27 quotedbl 0x27 shift dollar 0x27 altgr section 0x28 exclam 0x28 shift ssharp 0x28 altgr y 0x2c addupper numbersign 0x2d altgr ampersand 0x2e altgr at 0x2f altgr braceleft 0x30 altgr braceright 0x31 altgr comma 0x33 question 0x33 shift less 0x33 altgr period 0x34 colon 0x34 shift greater 0x34 altgr minus 0x35 underscore 0x35 shift asterisk 0x35 altgr rdesktop-1.8.3/keymaps/da0000664000770100510440000000502007645003603014255 0ustar hean01hean01# generated from XKB map dk include common map 0x406 exclam 0x02 shift exclamdown 0x02 altgr onesuperior 0x02 shift altgr quotedbl 0x03 shift at 0x03 altgr twosuperior 0x03 shift altgr numbersign 0x04 shift sterling 0x04 altgr threesuperior 0x04 shift altgr currency 0x05 shift dollar 0x05 altgr onequarter 0x05 shift altgr percent 0x06 shift onehalf 0x06 altgr cent 0x06 shift altgr ampersand 0x07 shift yen 0x07 altgr fiveeighths 0x07 shift altgr slash 0x08 shift braceleft 0x08 altgr division 0x08 shift altgr parenleft 0x09 shift bracketleft 0x09 altgr guillemotleft 0x09 shift altgr parenright 0x0a shift bracketright 0x0a altgr guillemotright 0x0a shift altgr equal 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr plus 0x0c question 0x0c shift plusminus 0x0c altgr questiondown 0x0c shift altgr dead_acute 0x0d dead_grave 0x0d shift bar 0x0d altgr brokenbar 0x0d shift altgr Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr cent 0x12 shift altgr registered 0x13 altgr thorn 0x14 altgr THORN 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oe 0x18 altgr OE 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr aring 0x1a Aring 0x1a shift dead_diaeresis 0x1a altgr dead_abovering 0x1a shift altgr dead_diaeresis 0x1b dead_circumflex 0x1b shift dead_tilde 0x1b altgr dead_caron 0x1b shift altgr ordfeminine 0x1e altgr masculine 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr ae 0x27 AE 0x27 shift oslash 0x28 Ooblique 0x28 shift dead_caron 0x28 shift altgr onehalf 0x29 section 0x29 shift threequarters 0x29 altgr paragraph 0x29 shift altgr apostrophe 0x2b asterisk 0x2b shift dead_doubleacute 0x2b altgr multiply 0x2b shift altgr guillemotleft 0x2c altgr guillemotright 0x2d altgr copyright 0x2e altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 semicolon 0x33 shift dead_cedilla 0x33 altgr dead_ogonek 0x33 shift altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr dead_abovedot 0x34 shift altgr minus 0x35 underscore 0x35 shift hyphen 0x35 altgr macron 0x35 shift altgr nobreakspace 0x39 altgr less 0x56 greater 0x56 shift backslash 0x56 altgr notsign 0x56 shift altgr rdesktop-1.8.3/keymaps/de0000664000770100510440000000464307561421245014276 0ustar hean01hean01# generated from XKB map de include common map 0x407 exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr quotedbl 0x03 shift twosuperior 0x03 altgr oneeighth 0x03 shift altgr section 0x04 shift threesuperior 0x04 altgr sterling 0x04 shift altgr dollar 0x05 shift onequarter 0x05 altgr currency 0x05 shift altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr ampersand 0x07 shift threequarters 0x07 altgr fiveeighths 0x07 shift altgr slash 0x08 shift braceleft 0x08 altgr seveneighths 0x08 shift altgr parenleft 0x09 shift bracketleft 0x09 altgr trademark 0x09 shift altgr parenright 0x0a shift bracketright 0x0a altgr plusminus 0x0a shift altgr equal 0x0b shift braceright 0x0b altgr ssharp 0x0c question 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr acute 0x0d dead_acute 0x0d grave 0x0d shift dead_grave 0x0d shift dead_cedilla 0x0d altgr dead_ogonek 0x0d shift altgr at 0x10 altgr Greek_OMEGA 0x10 shift altgr EuroSign 0x12 altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr z 0x15 addupper leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr udiaeresis 0x1a Udiaeresis 0x1a shift dead_diaeresis 0x1a altgr dead_abovering 0x1a shift altgr plus 0x1b asterisk 0x1b shift asciitilde 0x1b altgr dead_tilde 0x1b altgr dead_macron 0x1b shift altgr ae 0x1e altgr AE 0x1e shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr odiaeresis 0x27 Odiaeresis 0x27 shift dead_doubleacute 0x27 altgr adiaeresis 0x28 Adiaeresis 0x28 shift dead_caron 0x28 shift altgr asciicircum 0x29 dead_circumflex 0x29 degree 0x29 shift notsign 0x29 altgr numbersign 0x2b apostrophe 0x2b shift dead_breve 0x2b shift altgr y 0x2c addupper guillemotleft 0x2c altgr guillemotright 0x2d altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 semicolon 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr minus 0x35 underscore 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/es0000664000770100510440000000427407742757050014324 0ustar hean01hean01# generated from XKB map es include common map 0x40a exclam 0x02 shift bar 0x02 altgr quotedbl 0x03 shift at 0x03 altgr oneeighth 0x03 shift altgr periodcentered 0x04 shift numbersign 0x04 altgr sterling 0x04 shift altgr dollar 0x05 shift asciitilde 0x05 altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr ampersand 0x07 shift notsign 0x07 altgr fiveeighths 0x07 shift altgr slash 0x08 shift seveneighths 0x08 shift altgr parenleft 0x09 shift trademark 0x09 shift altgr parenright 0x0a shift plusminus 0x0a shift altgr equal 0x0b shift degree 0x0b shift altgr apostrophe 0x0c question 0x0c shift exclamdown 0x0d questiondown 0x0d shift Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr dead_grave 0x1a dead_circumflex 0x1a shift bracketleft 0x1a altgr dead_abovering 0x1a shift altgr plus 0x1b asterisk 0x1b shift bracketright 0x1b altgr dead_macron 0x1b shift altgr ae 0x1e altgr AE 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr ntilde 0x27 Ntilde 0x27 shift dead_doubleacute 0x27 shift altgr dead_acute 0x28 dead_diaeresis 0x28 shift braceleft 0x28 altgr masculine 0x29 ordfeminine 0x29 shift backslash 0x29 altgr ccedilla 0x2b Ccedilla 0x2b shift braceright 0x2b altgr dead_breve 0x2b shift altgr guillemotleft 0x2c altgr less 0x56 greater 0x56 shift guillemotright 0x2d altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr comma 0x33 semicolon 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 colon 0x34 shift division 0x34 shift altgr minus 0x35 underscore 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/et0000664000770100510440000000214110026127021014266 0ustar hean01hean01map 0x00000425 include common # # Top row # dead_caron 0x29 dead_tilde 0x29 shift # 1 exclam 0x2 shift # 2 quotedbl 0x3 shift at 0x3 altgr # 3 numbersign 0x4 shift sterling 0x4 altgr # 4 currency 0x5 shift dollar 0x5 altgr # 5 percent 0x6 shift # 6 ampersand 0x7 shift # 7 slash 0x8 shift braceleft 0x8 altgr # 8 parenleft 0x9 shift bracketleft 0x9 altgr # 9 parenright 0xa shift bracketright 0xa altgr # 0 equal 0xb shift braceright 0xb altgr plus 0xc question 0xc shift backslash 0xc altgr acute 0xd dead_acute 0xd grave 0xd shift dead_grave 0xd shift # # QWERTY first row # EuroSign 0x12 altgr udiaeresis 0x1a Udiaeresis 0x1a shift otilde 0x1b Otilde 0x1b shift section 0x1b altgr # # QWERTY second row # scaron 0x1f altgr Scaron 0x1f altgr shift odiaeresis 0x27 Odiaeresis 0x27 shift adiaeresis 0x28 Adiaeresis 0x28 shift asciicircum 0x28 altgr apostrophe 0x2b asterisk 0x2b shift onehalf 0x2b altgr # # QWERTY third row # less 0x56 greater 0x56 shift bar 0x56 altgr zcaron 0x2c altgr Zcaron 0x2c altgr shift comma 0x33 semicolon 0x33 shift period 0x34 colon 0x34 shift minus 0x35 underscore 0x35 shift rdesktop-1.8.3/keymaps/fi0000664000770100510440000000511710162626041014271 0ustar hean01hean01# Finnish keyboard layout # Originally generated from XKB map se_FI (wrong!), modified afterwards. include common map 0x40b exclam 0x02 shift exclamdown 0x02 altgr onesuperior 0x02 shift altgr quotedbl 0x03 shift at 0x03 altgr twosuperior 0x03 shift altgr numbersign 0x04 shift sterling 0x04 altgr threesuperior 0x04 shift altgr currency 0x05 shift dollar 0x05 altgr onequarter 0x05 shift altgr percent 0x06 shift onehalf 0x06 altgr cent 0x06 shift altgr ampersand 0x07 shift yen 0x07 altgr fiveeighths 0x07 shift altgr slash 0x08 shift braceleft 0x08 altgr division 0x08 shift altgr parenleft 0x09 shift bracketleft 0x09 altgr guillemotleft 0x09 shift altgr parenright 0x0a shift bracketright 0x0a altgr guillemotright 0x0a shift altgr equal 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr plus 0x0c question 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr dead_acute 0x0d dead_grave 0x0d shift plusminus 0x0d altgr notsign 0x0d shift altgr Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr cent 0x12 shift altgr registered 0x13 altgr thorn 0x14 altgr THORN 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oe 0x18 altgr OE 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr aring 0x1a Aring 0x1a shift dead_diaeresis 0x1a altgr dead_abovering 0x1a shift altgr dead_diaeresis 0x1b dead_circumflex 0x1b shift dead_tilde 0x1b altgr dead_caron 0x1b shift altgr ordfeminine 0x1e altgr masculine 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr odiaeresis 0x27 Odiaeresis 0x27 shift oslash 0x27 altgr Ooblique 0x27 shift altgr adiaeresis 0x28 Adiaeresis 0x28 shift ae 0x28 altgr AE 0x28 shift altgr section 0x29 onehalf 0x29 shift paragraph 0x29 altgr threequarters 0x29 shift altgr apostrophe 0x2b asterisk 0x2b shift acute 0x2b altgr multiply 0x2b shift altgr guillemotleft 0x2c altgr guillemotright 0x2d altgr copyright 0x2e altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 semicolon 0x33 shift dead_cedilla 0x33 altgr dead_ogonek 0x33 shift altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr dead_abovedot 0x34 shift altgr minus 0x35 underscore 0x35 shift hyphen 0x35 altgr macron 0x35 shift altgr nobreakspace 0x39 altgr rdesktop-1.8.3/keymaps/fo0000664000770100510440000000161307647174665014324 0ustar hean01hean01map 0x438 include common # # Top row # onehalf 0x29 section 0x29 shift # 1 exclam 0x2 shift # 2 quotedbl 0x3 shift at 0x3 altgr # 3 numbersign 0x4 shift sterling 0x4 altgr # 4 currency 0x5 shift dollar 0x5 altgr # 5 percent 0x6 shift # 6 ampersand 0x7 shift # 7 slash 0x8 shift braceleft 0x8 altgr # 8 parenleft 0x9 shift bracketleft 0x9 altgr # 9 parenright 0xa shift bracketright 0xa altgr # 0 equal 0xb shift braceright 0xb altgr plus 0xc question 0xc shift plusminus 0xc altgr bar 0xd altgr dead_acute 0xd # # QWERTY first row # EuroSign 0x12 altgr aring 0x1a Aring 0x1a shift eth 0x1b addupper asciitilde 0x1b altgr # # QWERTY second row # ae 0x27 addupper oslash 0x28 Ooblique 0x28 shift apostrophe 0x2b asterisk 0x2b shift # # QWERTY third row # less 0x56 greater 0x56 shift backslash 0x56 altgr comma 0x33 semicolon 0x33 shift period 0x34 colon 0x34 shift minus 0x35 underscore 0x35 shift rdesktop-1.8.3/keymaps/fr0000664000770100510440000000503407742755301014314 0ustar hean01hean01include common map 0x40c # # Top row # twosuperior 0x29 notsign 0x29 altgr ampersand 0x02 1 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr eacute 0x03 2 0x03 shift asciitilde 0x03 altgr oneeighth 0x03 shift altgr quotedbl 0x04 3 0x04 shift numbersign 0x04 altgr apostrophe 0x05 4 0x05 shift braceleft 0x05 altgr parenleft 0x06 5 0x06 shift bracketleft 0x06 altgr threeeighths 0x06 shift altgr minus 0x07 6 0x07 shift bar 0x07 altgr fiveeighths 0x07 shift altgr egrave 0x08 7 0x08 shift grave 0x08 altgr seveneighths 0x08 shift altgr underscore 0x09 8 0x09 shift backslash 0x09 altgr trademark 0x09 shift altgr ccedilla 0x0a 9 0x0a shift asciicircum 0x0a altgr plusminus 0x0a shift altgr agrave 0x0b 0 0x0b shift at 0x0b altgr parenright 0x0c degree 0x0c shift bracketright 0x0c altgr questiondown 0x0c shift altgr equal 0x0d plus 0x0d shift braceright 0x0d altgr dead_ogonek 0x0d shift altgr # # AZERTY first row # a 0x10 addupper ae 0x10 altgr AE 0x10 shift altgr z 0x11 addupper guillemotleft 0x11 altgr EuroSign 0x12 altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr dead_circumflex 0x1a dead_diaeresis 0x1a shift dead_abovering 0x1a shift altgr dollar 0x1b sterling 0x1b shift currency 0x1b altgr dead_macron 0x1b shift altgr # # AZERTY second row # q 0x1e addupper Greek_OMEGA 0x1e shift altgr ssharp 0x1f altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr m 0x27 addupper masculine 0x27 shift altgr ugrave 0x28 percent 0x28 shift dead_caron 0x28 shift altgr asterisk 0x2b mu 0x2b shift dead_grave 0x2b altgr dead_breve 0x2b shift altgr # # AZERTY third row # less 0x56 greater 0x56 shift w 0x2c addupper guillemotright 0x2d altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr rightdoublequotemark 0x30 altgr comma 0x32 question 0x32 shift dead_acute 0x32 altgr dead_doubleacute 0x32 shift altgr semicolon 0x33 period 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr colon 0x34 slash 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr exclam 0x35 section 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/he0000664000770100510440000000266110244667253014303 0ustar hean01hean01# Generated by Shlomil # Please send your comments and corrections to include common map 0x040D # # Top row # slash 0x10 altgr apostrophe 0x11 altgr hebrew_qoph 0x12 altgr hebrew_resh 0x13 altgr hebrew_aleph 0x14 altgr hebrew_tet 0x15 altgr hebrew_waw 0x16 altgr hebrew_finalnun 0x17 altgr hebrew_finalmem 0x18 altgr hebrew_pe 0x19 altgr # # Second row # hebrew_shin 0x1e altgr hebrew_dalet 0x1f altgr hebrew_gimel 0x20 altgr hebrew_kaph 0x21 altgr hebrew_ayin 0x22 altgr hebrew_yod 0x23 altgr hebrew_chet 0x24 altgr hebrew_lamed 0x25 altgr hebrew_finalkaph 0x26 altgr hebrew_finalpe 0x27 altgr comma 0x28 altgr # # Third row # hebrew_zain 0x2c altgr hebrew_samech 0x2d altgr hebrew_bet 0x2e altgr hebrew_he 0x2f altgr hebrew_nun 0x30 altgr hebrew_mem 0x31 altgr hebrew_zade 0x32 altgr hebrew_taw 0x33 altgr hebrew_finalzade 0x34 altgr period 0x35 altgr # # en-us # exclam 0x02 shift at 0x03 shift numbersign 0x04 shift dollar 0x05 shift percent 0x06 shift asciicircum 0x07 shift ampersand 0x08 shift asterisk 0x09 shift parenleft 0x0a shift parenright 0x0b shift minus 0x0c underscore 0x0c shift equal 0x0d plus 0x0d shift bracketleft 0x1a braceleft 0x1a shift bracketright 0x1b braceright 0x1b shift semicolon 0x27 colon 0x27 shift apostrophe 0x28 quotedbl 0x28 shift grave 0x29 asciitilde 0x29 shift backslash 0x2b bar 0x2b shift comma 0x33 less 0x33 shift period 0x34 greater 0x34 shift slash 0x35 question 0x35 shift rdesktop-1.8.3/keymaps/hr0000664000770100510440000000521307554011737014314 0ustar hean01hean01# generated from XKB map hr include common map 0x41a exclam 0x02 shift asciitilde 0x02 altgr dead_tilde 0x02 shift altgr quotedbl 0x03 shift dead_caron 0x03 altgr caron 0x03 shift altgr numbersign 0x04 shift asciicircum 0x04 altgr dead_circumflex 0x04 shift altgr dollar 0x05 shift dead_breve 0x05 altgr breve 0x05 shift altgr percent 0x06 shift degree 0x06 altgr dead_abovering 0x06 shift altgr ampersand 0x07 shift dead_ogonek 0x07 altgr ogonek 0x07 shift altgr slash 0x08 shift grave 0x08 altgr dead_grave 0x08 shift altgr parenleft 0x09 shift dead_abovedot 0x09 altgr abovedot 0x09 shift altgr parenright 0x0a shift dead_acute 0x0a altgr apostrophe 0x0a shift altgr equal 0x0b shift dead_doubleacute 0x0b altgr doubleacute 0x0b shift altgr apostrophe 0x0c question 0x0c shift dead_diaeresis 0x0c altgr diaeresis 0x0c shift altgr plus 0x0d asterisk 0x0d shift dead_cedilla 0x0d altgr cedilla 0x0d shift altgr backslash 0x10 altgr Greek_OMEGA 0x10 shift altgr bar 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr z 0x15 addupper leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr scaron 0x1a Scaron 0x1a shift division 0x1a altgr dead_abovering 0x1a shift altgr dstroke 0x1b Dstroke 0x1b shift multiply 0x1b altgr dead_macron 0x1b shift altgr ae 0x1e altgr AE 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr bracketleft 0x21 altgr ordfeminine 0x21 shift altgr bracketright 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr lstroke 0x25 altgr ampersand 0x25 shift altgr Lstroke 0x26 altgr ccaron 0x27 Ccaron 0x27 shift dead_acute 0x27 altgr dead_doubleacute 0x27 shift altgr cacute 0x28 Cacute 0x28 shift ssharp 0x28 altgr dead_caron 0x28 shift altgr dead_cedilla 0x29 dead_diaeresis 0x29 shift notsign 0x29 altgr zcaron 0x2b Zcaron 0x2b shift currency 0x2b altgr dead_breve 0x2b shift altgr y 0x2c addupper guillemotleft 0x2c altgr less 0x2c shift altgr guillemotright 0x2d altgr greater 0x2d shift altgr cent 0x2e altgr copyright 0x2e shift altgr at 0x2f altgr grave 0x2f shift altgr braceleft 0x30 altgr apostrophe 0x30 shift altgr braceright 0x31 altgr section 0x32 altgr masculine 0x32 shift altgr comma 0x33 semicolon 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr minus 0x35 underscore 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/hu0000664000770100510440000000351207716112403014307 0ustar hean01hean01# Hungarian keyboard layout (QWERTZ) # Created by: The NeverGone include common map 0x40e # AltGr keys: notsign 0x29 altgr asciitilde 0x02 altgr caron 0x03 altgr asciicircum 0x04 altgr breve 0x05 altgr degree 0x06 altgr ogonek 0x07 altgr grave 0x08 altgr abovedot 0x09 altgr acute 0x0a altgr doubleacute 0x0b altgr diaeresis 0x0c altgr cedilla 0x0d altgr backslash 0x10 altgr bar 0x11 altgr EuroSign 0x12 altgr Iacute 0x17 altgr division 0x1a altgr multiply 0x1b altgr dstroke 0x1f altgr Dstroke 0x20 altgr bracketleft 0x21 altgr bracketright 0x22 altgr iacute 0x24 altgr lstroke 0x25 altgr Lstroke 0x26 altgr dollar 0x27 altgr ssharp 0x28 altgr currency 0x2b altgr less 0x56 altgr greater 0x2c altgr numbersign 0x2d altgr ampersand 0x2e altgr at 0x2f altgr braceleft 0x30 altgr braceright 0x31 altgr semicolon 0x33 altgr asterisk 0x35 altgr # Shift keys: section 0x29 shift apostrophe 0x02 shift quotedbl 0x03 shift plus 0x04 shift exclam 0x05 shift percent 0x06 shift slash 0x07 shift equal 0x08 shift parenleft 0x09 shift parenright 0x0a shift Odiaeresis 0x0b shift Udiaeresis 0x0c shift Oacute 0x0d shift Z 0x15 shift Odoubleacute 0x1a shift Uacute 0x1b shift Eacute 0x27 shift Aacute 0x28 shift Udoubleacute 0x2b shift Y 0x2c shift question 0x33 shift colon 0x34 shift underscore 0x35 shift F13 0x3b shift F14 0x3c shift F15 0x3d shift F16 0x3e shift F17 0x3f shift F18 0x40 shift F19 0x41 shift F20 0x42 shift F21 0x43 shift F22 0x44 shift F23 0x57 shift F24 0x58 shift # Ctrl keys: F25 0x3b ctrl F26 0x3c ctrl F27 0x3d ctrl F28 0x3e ctrl F29 0x3f ctrl F30 0x40 ctrl F31 0x41 ctrl F32 0x42 ctrl F33 0x43 ctrl F34 0x44 ctrl F35 0x57 ctrl #NoSymbol 0x58 ctrl 0 0x29 odiaeresis 0x0b udiaeresis 0x0c oacute 0x0d z 0x15 odoubleacute 0x1a uacute 0x1b eacute 0x27 aacute 0x28 udoubleacute 0x2b y 0x2c comma 0x33 period 0x34 minus 0x35 rdesktop-1.8.3/keymaps/is0000664000770100510440000000600510562615252014311 0ustar hean01hean01# 2004-03-16 Halldór Guðmundsson and Morten Lange # Keyboard definition file for the Icelandic keyboard # to be used in rdesktop 1.3.x ( See rdesktop.org) # generated from XKB map de, and changed manually # Location for example /usr/local/share/rdesktop/keymaps/is include common map 0x40f exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr quotedbl 0x03 shift twosuperior 0x03 altgr oneeighth 0x03 shift altgr #section 0x04 shift numbersign 0x04 shift threesuperior 0x04 altgr sterling 0x04 shift altgr dollar 0x05 shift onequarter 0x05 altgr currency 0x05 shift altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr ampersand 0x07 shift threequarters 0x07 altgr fiveeighths 0x07 shift altgr slash 0x08 shift braceleft 0x08 altgr seveneighths 0x08 shift altgr parenleft 0x09 shift bracketleft 0x09 altgr trademark 0x09 shift altgr parenright 0x0a shift bracketright 0x0a altgr plusminus 0x0a shift altgr equal 0x0b shift braceright 0x0b altgr #ssharp 0x0c odiaeresis 0x0c #question 0x0c shift Odiaeresis 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr #acute 0x0d minus 0x0d #dead_acute 0x0d #grave 0x0d shift #dead_grave 0x0d shift underscore 0x0d shift dead_cedilla 0x0d altgr dead_ogonek 0x0d shift altgr at 0x10 altgr Greek_OMEGA 0x10 shift altgr EuroSign 0x12 altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr #z 0x15 addupper leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr #thorn 0x19 altgr #THORN 0x19 shift altgr #udiaeresis 0x1a #Udiaeresis 0x1a shift #dead_diaeresis 0x1a altgr #dead_abovering 0x1a shift altgr eth 0x1a ETH 0x1a shift apostrophe 0x1b question 0x1b shift #plus 0x1b #asterisk 0x1b shift asciitilde 0x1b altgr #grave 0x1b altgr #dead_tilde 0x1b altgr #dead_macron 0x1b shift altgr #ae 0x1e altgr #AE 0x1e shift altgr #eth 0x20 altgr #eth 0x20 #ETH 0x20 shift altgr #ETH 0x20 shift dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr #adiaeresis 0x27 #Adiaeresis 0x27 shift ae 0x27 AE 0x27 shift dead_doubleacute 0x27 altgr #adiaeresis 0x28 #Adiaeresis 0x28 shift #dead_caron 0x28 shift altgr #asciicircum 0x29 acute 0x28 dead_acute 0x28 #dead_circumflex 0x29 #degree 0x29 shift #notsign 0x29 altgr plus 0x2b asterisk 0x2b shift grave 0x2b altgr #numbersign 0x2b #apostrophe 0x2b shift #dead_breve 0x2b shift altgr #y 0x2c addupper guillemotleft 0x2c altgr guillemotright 0x2d altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 semicolon 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr #minus 0x35 #underscore 0x35 shift thorn 0x35 THORN 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/it0000664000770100510440000000455512026335636014324 0ustar hean01hean01# generated from XKB map it include common map 0x410 exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr quotedbl 0x03 shift twosuperior 0x03 altgr oneeighth 0x03 shift altgr sterling 0x04 shift threesuperior 0x04 altgr dollar 0x05 shift onequarter 0x05 altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr ampersand 0x07 shift threequarters 0x07 altgr fiveeighths 0x07 shift altgr slash 0x08 shift seveneighths 0x08 shift altgr parenleft 0x09 shift trademark 0x09 shift altgr parenright 0x0a shift plusminus 0x0a shift altgr equal 0x0b shift degree 0x0b shift altgr apostrophe 0x0c question 0x0c shift grave 0x0c altgr questiondown 0x0c shift altgr igrave 0x0d asciicircum 0x0d shift asciitilde 0x0d altgr dead_ogonek 0x0d shift altgr at 0x10 altgr Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr cent 0x12 shift altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr egrave 0x1a eacute 0x1a shift bracketleft 0x1a altgr braceleft 0x1a shift altgr plus 0x1b asterisk 0x1b shift bracketright 0x1b altgr braceright 0x1b shift altgr ae 0x1e altgr AE 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr ograve 0x27 ccedilla 0x27 shift at 0x27 altgr dead_doubleacute 0x27 shift altgr agrave 0x28 degree 0x28 shift numbersign 0x28 altgr backslash 0x29 bar 0x29 shift notsign 0x29 altgr ugrave 0x2b section 0x2b shift dead_grave 0x2b altgr dead_breve 0x2b shift altgr guillemotleft 0x2c altgr guillemotright 0x2d altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 semicolon 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr minus 0x35 underscore 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/ja0000664000770100510440000000501711357620741014274 0ustar hean01hean01# generated from XKB map jp106 # See OADG Technical reference for official scancodes: # http://www.oadg.or.jp/tosho/index.htm#techref include common map 0xe0010411 keyboard_type 0x7 keyboard_subtype 0x2 keyboard_functionkeys 0xc exclam 0x02 shift kana_NU 0x02 altgr quotedbl 0x03 shift kana_FU 0x03 altgr numbersign 0x04 shift kana_A 0x04 altgr kana_a 0x04 shift altgr dollar 0x05 shift kana_U 0x05 altgr kana_u 0x05 shift altgr percent 0x06 shift kana_E 0x06 altgr kana_e 0x06 shift altgr ampersand 0x07 shift kana_O 0x07 altgr kana_o 0x07 shift altgr apostrophe 0x08 shift kana_YA 0x08 altgr kana_ya 0x08 shift altgr parenleft 0x09 shift kana_YU 0x09 altgr kana_yu 0x09 shift altgr parenright 0x0a shift kana_YO 0x0a altgr kana_yo 0x0a shift altgr asciitilde 0x0b shift kana_WA 0x0b altgr kana_WO 0x0b shift altgr minus 0x0c equal 0x0c shift kana_HO 0x0c altgr asciicircum 0x0d asciitilde 0x0d shift kana_HE 0x0d altgr kana_TA 0x10 altgr kana_TE 0x11 altgr kana_I 0x12 altgr kana_i 0x12 shift altgr kana_SU 0x13 altgr kana_KA 0x14 altgr kana_N 0x15 altgr kana_NA 0x16 altgr kana_NI 0x17 altgr kana_RA 0x18 altgr kana_SE 0x19 altgr at 0x1a grave 0x1a shift voicedsound 0x1a altgr bracketleft 0x1b braceleft 0x1b shift semivoicedsound 0x1b altgr kana_openingbracket 0x1b shift altgr kana_CHI 0x1e altgr kana_TO 0x1f altgr kana_SHI 0x20 altgr kana_HA 0x21 altgr kana_KI 0x22 altgr kana_KU 0x23 altgr kana_MA 0x24 altgr kana_NO 0x25 altgr kana_RI 0x26 altgr semicolon 0x27 plus 0x27 shift kana_RE 0x27 altgr colon 0x28 asterisk 0x28 shift kana_KE 0x28 altgr Zenkaku_Hankaku 0x29 Kanji 0x29 bracketright 0x2b braceright 0x2b shift kana_MU 0x2b altgr kana_closingbracket 0x2b shift altgr kana_TSU 0x2c altgr kana_tsu 0x2c shift altgr kana_SA 0x2d altgr kana_SO 0x2e altgr kana_HI 0x2f altgr kana_KO 0x30 altgr kana_MI 0x31 altgr kana_MO 0x32 altgr comma 0x33 less 0x33 shift kana_NE 0x33 altgr kana_comma 0x33 shift altgr period 0x34 greater 0x34 shift kana_RU 0x34 altgr kana_fullstop 0x34 shift altgr slash 0x35 question 0x35 shift kana_ME 0x35 altgr kana_conjunctive 0x35 shift altgr Execute 0x54 shift backslash 0x73 bar 0x7d shift underscore 0x73 shift Henkan_Mode 0x79 Hiragana_Katakana 0x70 localstate Katakana 0x70 Romaji 0x70 Muhenkan 0x7b # Plain [Eisu_toggle/Caps_Lock] should NOT have shift Eisu_toggle 0x3a # [Eisu_toggle/Caps_Lock] key will generate Caps_Lock keysym # only with shift+capslock stroke. Windows also expect this, so prefix a shift Caps_Lock 0x3a shift # Windows,Menu F13 0xdc Menu 0xdd #todo: Alt_R+Romaji doesnt romaji the IME (Alt_L+Romaji works) rdesktop-1.8.3/keymaps/ko0000664000770100510440000000120410356020106014270 0ustar hean01hean01# generated from XKB map ko include common map 0xe0010412 exclam 0x02 shift at 0x03 shift numbersign 0x04 shift dollar 0x05 shift percent 0x06 shift asciicircum 0x07 shift ampersand 0x08 shift asterisk 0x09 shift parenleft 0x0a shift parenright 0x0b shift minus 0x0c underscore 0x0c shift equal 0x0d plus 0x0d shift bracketleft 0x1a braceleft 0x1a shift bracketright 0x1b braceright 0x1b shift semicolon 0x27 colon 0x27 shift apostrophe 0x28 quotedbl 0x28 shift grave 0x29 asciitilde 0x29 shift backslash 0x2b bar 0x2b shift comma 0x33 less 0x33 shift period 0x34 greater 0x34 shift slash 0x35 question 0x35 shift Hangul 0xf2 Hangul_Hanja 0xf1 rdesktop-1.8.3/keymaps/lt0000664000770100510440000000211007554011737014313 0ustar hean01hean01# generated from XKB map lt include common map 0x427 exclam 0x02 shift aogonek 0x02 altgr Aogonek 0x02 shift altgr at 0x03 shift ccaron 0x03 altgr Ccaron 0x03 shift altgr numbersign 0x04 shift eogonek 0x04 altgr Eogonek 0x04 shift altgr dollar 0x05 shift eabovedot 0x05 altgr Eabovedot 0x05 shift altgr percent 0x06 shift iogonek 0x06 altgr Iogonek 0x06 shift altgr asciicircum 0x07 shift scaron 0x07 altgr Scaron 0x07 shift altgr ampersand 0x08 shift uogonek 0x08 altgr Uogonek 0x08 shift altgr asterisk 0x09 shift umacron 0x09 altgr Umacron 0x09 shift altgr parenleft 0x0a shift doublelowquotemark 0x0a altgr parenright 0x0b shift leftdoublequotemark 0x0b altgr minus 0x0c underscore 0x0c shift equal 0x0d plus 0x0d shift zcaron 0x0d altgr Zcaron 0x0d shift altgr bracketleft 0x1a braceleft 0x1a shift bracketright 0x1b braceright 0x1b shift semicolon 0x27 colon 0x27 shift apostrophe 0x28 quotedbl 0x28 shift grave 0x29 asciitilde 0x29 shift backslash 0x2b bar 0x2b shift comma 0x33 less 0x33 shift period 0x34 greater 0x34 shift slash 0x35 question 0x35 shift endash 0x56 EuroSign 0x56 shift rdesktop-1.8.3/keymaps/lv0000664000770100510440000000543007554011737014325 0ustar hean01hean01# generated from XKB map lv include common map 0x426 exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr at 0x03 shift twosuperior 0x03 altgr oneeighth 0x03 shift altgr numbersign 0x04 shift threesuperior 0x04 altgr sterling 0x04 shift altgr dollar 0x05 shift EuroSign 0x05 altgr cent 0x05 shift altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr asciicircum 0x07 shift threequarters 0x07 altgr fiveeighths 0x07 shift altgr ampersand 0x08 shift braceleft 0x08 altgr seveneighths 0x08 shift altgr asterisk 0x09 shift bracketleft 0x09 altgr trademark 0x09 shift altgr parenleft 0x0a shift bracketright 0x0a altgr plusminus 0x0a shift altgr parenright 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr minus 0x0c underscore 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr equal 0x0d plus 0x0d shift dead_cedilla 0x0d altgr dead_ogonek 0x0d shift altgr at 0x10 altgr Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr emacron 0x12 altgr Emacron 0x12 shift altgr rcedilla 0x13 altgr Rcedilla 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr umacron 0x16 altgr Umacron 0x16 shift altgr imacron 0x17 altgr Imacron 0x17 shift altgr omacron 0x18 altgr Omacron 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr bracketleft 0x1a braceleft 0x1a shift dead_diaeresis 0x1a altgr dead_abovering 0x1a shift altgr bracketright 0x1b braceright 0x1b shift dead_tilde 0x1b altgr dead_macron 0x1b shift altgr ISO_Next_Group 0x1c shift amacron 0x1e altgr Amacron 0x1e shift altgr scaron 0x1f altgr Scaron 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr gcedilla 0x22 altgr Gcedilla 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kcedilla 0x25 altgr Kcedilla 0x25 shift altgr lcedilla 0x26 altgr Lcedilla 0x26 shift altgr semicolon 0x27 colon 0x27 shift dead_acute 0x27 altgr dead_doubleacute 0x27 shift altgr apostrophe 0x28 quotedbl 0x28 shift leftdoublequotemark 0x28 altgr doublelowquotemark 0x28 shift altgr grave 0x29 asciitilde 0x29 shift notsign 0x29 altgr backslash 0x2b bar 0x2b shift dead_grave 0x2b altgr dead_breve 0x2b shift altgr zcaron 0x2c altgr Zcaron 0x2c shift altgr guillemotright 0x2d altgr greater 0x2d shift altgr ccaron 0x2e altgr Ccaron 0x2e shift altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr apostrophe 0x30 shift altgr ncedilla 0x31 altgr Ncedilla 0x31 shift altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 less 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 greater 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr slash 0x35 question 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr nobreakspace 0x39 altgr rdesktop-1.8.3/keymaps/mk0000664000770100510440000000447607554011737014324 0ustar hean01hean01# generated from XKB map mk include common map 0x42f exclam 0x02 shift at 0x03 shift doublelowquotemark 0x03 shift altgr numbersign 0x04 shift leftdoublequotemark 0x04 shift altgr dollar 0x05 shift percent 0x06 shift asciicircum 0x07 shift ampersand 0x08 shift asterisk 0x09 shift parenleft 0x0a shift parenright 0x0b shift minus 0x0c underscore 0x0c shift equal 0x0d plus 0x0d shift Cyrillic_lje 0x10 altgr Cyrillic_LJE 0x10 shift altgr Cyrillic_nje 0x11 altgr Cyrillic_NJE 0x11 shift altgr Cyrillic_ie 0x12 altgr Cyrillic_IE 0x12 shift altgr Cyrillic_er 0x13 altgr Cyrillic_ER 0x13 shift altgr Cyrillic_te 0x14 altgr Cyrillic_TE 0x14 shift altgr Macedonia_dse 0x15 altgr Macedonia_DSE 0x15 shift altgr Cyrillic_u 0x16 altgr Cyrillic_U 0x16 shift altgr Cyrillic_i 0x17 altgr Cyrillic_I 0x17 shift altgr Cyrillic_o 0x18 altgr Cyrillic_O 0x18 shift altgr Cyrillic_pe 0x19 altgr Cyrillic_PE 0x19 shift altgr bracketleft 0x1a braceleft 0x1a shift Cyrillic_sha 0x1a altgr Cyrillic_SHA 0x1a shift altgr bracketright 0x1b braceright 0x1b shift Macedonia_gje 0x1b altgr Macedonia_GJE 0x1b shift altgr Cyrillic_a 0x1e altgr Cyrillic_A 0x1e shift altgr Cyrillic_es 0x1f altgr Cyrillic_ES 0x1f shift altgr Cyrillic_de 0x20 altgr Cyrillic_DE 0x20 shift altgr Cyrillic_ef 0x21 altgr Cyrillic_EF 0x21 shift altgr Cyrillic_ghe 0x22 altgr Cyrillic_GHE 0x22 shift altgr Cyrillic_ha 0x23 altgr Cyrillic_HA 0x23 shift altgr Cyrillic_je 0x24 altgr Cyrillic_JE 0x24 shift altgr Cyrillic_ka 0x25 altgr Cyrillic_KA 0x25 shift altgr Cyrillic_el 0x26 altgr Cyrillic_EL 0x26 shift altgr semicolon 0x27 colon 0x27 shift Cyrillic_che 0x27 altgr Cyrillic_CHE 0x27 shift altgr apostrophe 0x28 quotedbl 0x28 shift Macedonia_kje 0x28 altgr Macedonia_KJE 0x28 shift altgr grave 0x29 asciitilde 0x29 shift backslash 0x2b bar 0x2b shift Cyrillic_zhe 0x2b altgr Cyrillic_ZHE 0x2b shift altgr Cyrillic_ze 0x2c altgr Cyrillic_ZE 0x2c shift altgr Cyrillic_dzhe 0x2d altgr Cyrillic_DZHE 0x2d shift altgr Cyrillic_tse 0x2e altgr Cyrillic_TSE 0x2e shift altgr Cyrillic_ve 0x2f altgr Cyrillic_VE 0x2f shift altgr Cyrillic_be 0x30 altgr Cyrillic_BE 0x30 shift altgr Cyrillic_en 0x31 altgr Cyrillic_EN 0x31 shift altgr Cyrillic_em 0x32 altgr Cyrillic_EM 0x32 shift altgr comma 0x33 less 0x33 shift semicolon 0x33 shift altgr period 0x34 greater 0x34 shift colon 0x34 shift altgr slash 0x35 question 0x35 shift rdesktop-1.8.3/keymaps/nl0000664000770100510440000000212212323213700014270 0ustar hean01hean01# Dutch (Netherlands) include common map 0x413 exclam 0x02 shift onesuperior 0x02 altgr quotebl 0x03 shift twosuperior 0x03 altgr numbersign 0x04 shift threesuperior 0x04 altgr dollar 0x05 shift onequarter 0x05 altgr percent 0x06 shift onehalf 0x06 altgr ampersand 0x07 shift threequarters 0x07 altgr underscore 0x08 shift sterling 0x08 altgr parenleft 0x09 shift braceleft 0x09 altgr parenright 0x0a shift braceright 0x0a altgr apostrophe 0x0b shift slash 0x0c question 0x0c shift backslash 0x0c altgr degree 0x0d dead_tilde 0x0d shift dead_cedilla 0x0d altgr EuroSign 0x12 altgr paragraph 0x13 altgr dead_diaeresis 0x1a dead_circumflex 0x1a shift asterisk 0x1b bar 0x1b shift ssharp 0x1f altgr plus 0x27 plusminus 0x27 shift dead_acute 0x28 dead_grave 0x28 shift at 0x29 section 0x29 shift notsign 0x29 altgr less 0x2b greater 0x2b shift guillemotleft 0x2c altgr guillemotright 0x2d altgr copyright 0x2e altgr mu 0x32 altgr comma 0x33 semicolon 0x33 shift period 0x34 colon 0x34 shift periodcentered 0x34 altgr minus 0x35 equal 0x35 shift bracketright 0x56 bracketleft 0x56 shift brokenbar 0x56 altgr rdesktop-1.8.3/keymaps/no0000664000770100510440000000502007620224525014306 0ustar hean01hean01# generated from XKB map no include common map 0x414 exclam 0x02 shift exclamdown 0x02 altgr onesuperior 0x02 shift altgr quotedbl 0x03 shift at 0x03 altgr twosuperior 0x03 shift altgr numbersign 0x04 shift sterling 0x04 altgr threesuperior 0x04 shift altgr currency 0x05 shift dollar 0x05 altgr onequarter 0x05 shift altgr percent 0x06 shift onehalf 0x06 altgr cent 0x06 shift altgr ampersand 0x07 shift yen 0x07 altgr fiveeighths 0x07 shift altgr slash 0x08 shift braceleft 0x08 altgr division 0x08 shift altgr parenleft 0x09 shift bracketleft 0x09 altgr guillemotleft 0x09 shift altgr parenright 0x0a shift bracketright 0x0a altgr guillemotright 0x0a shift altgr equal 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr plus 0x0c question 0x0c shift plusminus 0x0c altgr questiondown 0x0c shift altgr backslash 0x0d dead_grave 0x0d shift dead_acute 0x0d altgr notsign 0x0d shift altgr Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr cent 0x12 shift altgr registered 0x13 altgr thorn 0x14 altgr THORN 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oe 0x18 altgr OE 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr aring 0x1a Aring 0x1a shift dead_diaeresis 0x1a altgr dead_abovering 0x1a shift altgr dead_diaeresis 0x1b dead_circumflex 0x1b shift asciicircum 0x01b shift dead_tilde 0x1b altgr asciitilde 0x1b altgr dead_caron 0x1b shift altgr ordfeminine 0x1e altgr masculine 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr oslash 0x27 Ooblique 0x27 shift dead_doubleacute 0x27 shift altgr ae 0x28 AE 0x28 shift dead_caron 0x28 shift altgr bar 0x29 section 0x29 shift brokenbar 0x29 altgr paragraph 0x29 shift altgr apostrophe 0x2b asterisk 0x2b shift multiply 0x2b shift altgr guillemotleft 0x2c altgr guillemotright 0x2d altgr copyright 0x2e altgr leftdoublequotemark 0x2f altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 semicolon 0x33 shift dead_cedilla 0x33 altgr dead_ogonek 0x33 shift altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr dead_abovedot 0x34 shift altgr minus 0x35 underscore 0x35 shift hyphen 0x35 altgr macron 0x35 shift altgr nobreakspace 0x39 altgr onehalf 0x56 altgr threequarters 0x56 shift altgr rdesktop-1.8.3/keymaps/pl0000664000770100510440000000516007742762054014323 0ustar hean01hean01# generated from XKB map pl include common map 0x415 exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr at 0x03 shift twosuperior 0x03 altgr oneeighth 0x03 shift altgr numbersign 0x04 shift threesuperior 0x04 altgr sterling 0x04 shift altgr dollar 0x05 shift onequarter 0x05 altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr asciicircum 0x07 shift threequarters 0x07 altgr fiveeighths 0x07 shift altgr ampersand 0x08 shift braceleft 0x08 altgr seveneighths 0x08 shift altgr asterisk 0x09 shift bracketleft 0x09 altgr trademark 0x09 shift altgr parenleft 0x0a shift bracketright 0x0a altgr plusminus 0x0a shift altgr parenright 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr minus 0x0c underscore 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr equal 0x0d plus 0x0d shift dead_cedilla 0x0d altgr dead_ogonek 0x0d shift altgr Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr eogonek 0x12 altgr Eogonek 0x12 shift altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr EuroSign 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oacute 0x18 altgr Oacute 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr bracketleft 0x1a braceleft 0x1a shift dead_diaeresis 0x1a altgr dead_abovering 0x1a shift altgr bracketright 0x1b braceright 0x1b shift dead_tilde 0x1b altgr dead_macron 0x1b shift altgr aogonek 0x1e altgr Aogonek 0x1e shift altgr sacute 0x1f altgr Sacute 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr semicolon 0x27 colon 0x27 shift dead_acute 0x27 altgr dead_doubleacute 0x27 shift altgr apostrophe 0x28 quotedbl 0x28 shift dead_circumflex 0x28 altgr dead_caron 0x28 shift altgr grave 0x29 asciitilde 0x29 shift notsign 0x29 altgr backslash 0x2b bar 0x2b shift dead_grave 0x2b altgr dead_breve 0x2b shift altgr zabovedot 0x2c altgr Zabovedot 0x2c shift altgr zacute 0x2d altgr Zacute 0x2d shift altgr cacute 0x2e altgr Cacute 0x2e shift altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr nacute 0x31 altgr Nacute 0x31 shift altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 less 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 greater 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr slash 0x35 question 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/pt0000664000770100510440000000462207762077306014336 0ustar hean01hean01# generated from XKB map pt include common map 0x816 exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr quotedbl 0x03 shift at 0x03 altgr oneeighth 0x03 shift altgr numbersign 0x04 shift sterling 0x04 altgr dollar 0x05 shift section 0x05 altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr ampersand 0x07 shift threequarters 0x07 altgr fiveeighths 0x07 shift altgr slash 0x08 shift braceleft 0x08 altgr seveneighths 0x08 shift altgr parenleft 0x09 shift bracketleft 0x09 altgr trademark 0x09 shift altgr parenright 0x0a shift bracketright 0x0a altgr plusminus 0x0a shift altgr equal 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr apostrophe 0x0c question 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr guillemotleft 0x0d guillemotright 0x0d shift dead_cedilla 0x0d altgr dead_ogonek 0x0d shift altgr Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr cent 0x12 shift altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr plus 0x1a asterisk 0x1a shift dead_diaeresis 0x1a altgr dead_abovering 0x1a shift altgr dead_acute 0x1b dead_grave 0x1b shift dead_tilde 0x1b altgr dead_macron 0x1b shift altgr ae 0x1e altgr AE 0x1e shift altgr ssharp 0x1f altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr ccedilla 0x27 Ccedilla 0x27 shift dead_doubleacute 0x27 shift altgr masculine 0x28 ordfeminine 0x28 shift dead_circumflex 0x28 altgr dead_caron 0x28 shift altgr backslash 0x29 bar 0x29 shift notsign 0x29 altgr dead_tilde 0x2b dead_circumflex 0x2b shift dead_breve 0x2b shift altgr less 0x56 greater 0x56 shift cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr comma 0x33 semicolon 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr minus 0x35 underscore 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/ru0000664000770100510440000000477207554011737014342 0ustar hean01hean01# generated from XKB map ru include common map 0x419 exclam 0x02 shift at 0x03 shift quotedbl 0x03 shift altgr numbersign 0x04 shift dollar 0x05 shift asterisk 0x05 shift altgr percent 0x06 shift colon 0x06 shift altgr asciicircum 0x07 shift comma 0x07 shift altgr ampersand 0x08 shift period 0x08 shift altgr asterisk 0x09 shift semicolon 0x09 shift altgr parenleft 0x0a shift parenright 0x0b shift minus 0x0c underscore 0x0c shift equal 0x0d plus 0x0d shift Cyrillic_shorti 0x10 altgr Cyrillic_SHORTI 0x10 shift altgr Cyrillic_tse 0x11 altgr Cyrillic_TSE 0x11 shift altgr Cyrillic_u 0x12 altgr Cyrillic_U 0x12 shift altgr Cyrillic_ka 0x13 altgr Cyrillic_KA 0x13 shift altgr Cyrillic_ie 0x14 altgr Cyrillic_IE 0x14 shift altgr Cyrillic_en 0x15 altgr Cyrillic_EN 0x15 shift altgr Cyrillic_ghe 0x16 altgr Cyrillic_GHE 0x16 shift altgr Cyrillic_sha 0x17 altgr Cyrillic_SHA 0x17 shift altgr Cyrillic_shcha 0x18 altgr Cyrillic_SHCHA 0x18 shift altgr Cyrillic_ze 0x19 altgr Cyrillic_ZE 0x19 shift altgr bracketleft 0x1a braceleft 0x1a shift Cyrillic_ha 0x1a altgr Cyrillic_HA 0x1a shift altgr bracketright 0x1b braceright 0x1b shift Cyrillic_hardsign 0x1b altgr Cyrillic_HARDSIGN 0x1b shift altgr Cyrillic_ef 0x1e altgr Cyrillic_EF 0x1e shift altgr Cyrillic_yeru 0x1f altgr Cyrillic_YERU 0x1f shift altgr Cyrillic_ve 0x20 altgr Cyrillic_VE 0x20 shift altgr Cyrillic_a 0x21 altgr Cyrillic_A 0x21 shift altgr Cyrillic_pe 0x22 altgr Cyrillic_PE 0x22 shift altgr Cyrillic_er 0x23 altgr Cyrillic_ER 0x23 shift altgr Cyrillic_o 0x24 altgr Cyrillic_O 0x24 shift altgr Cyrillic_el 0x25 altgr Cyrillic_EL 0x25 shift altgr Cyrillic_de 0x26 altgr Cyrillic_DE 0x26 shift altgr semicolon 0x27 colon 0x27 shift Cyrillic_zhe 0x27 altgr Cyrillic_ZHE 0x27 shift altgr apostrophe 0x28 quotedbl 0x28 shift Cyrillic_e 0x28 altgr Cyrillic_E 0x28 shift altgr grave 0x29 asciitilde 0x29 shift Cyrillic_io 0x29 altgr Cyrillic_IO 0x29 shift altgr backslash 0x2b bar 0x2b shift Cyrillic_ya 0x2c altgr Cyrillic_YA 0x2c shift altgr Cyrillic_che 0x2d altgr Cyrillic_CHE 0x2d shift altgr Cyrillic_es 0x2e altgr Cyrillic_ES 0x2e shift altgr Cyrillic_em 0x2f altgr Cyrillic_EM 0x2f shift altgr Cyrillic_i 0x30 altgr Cyrillic_I 0x30 shift altgr Cyrillic_te 0x31 altgr Cyrillic_TE 0x31 shift altgr Cyrillic_softsign 0x32 altgr Cyrillic_SOFTSIGN 0x32 shift altgr comma 0x33 less 0x33 shift Cyrillic_be 0x33 altgr Cyrillic_BE 0x33 shift altgr period 0x34 greater 0x34 shift Cyrillic_yu 0x34 altgr Cyrillic_YU 0x34 shift altgr slash 0x35 question 0x35 shift slash 0x56 altgr bar 0x56 shift altgr rdesktop-1.8.3/keymaps/sk0000664000770100510440000000610112243650240014302 0ustar hean01hean01#Slovak keymap #2007-05-28 by Jaroslav Jiricka include common #Additional sequences #2007-05-28 by Jaroslav Jiricka sequence ecaron dead_caron e sequence Ecaron dead_caron E sequence eogonek dead_ogonek e sequence Eogonek dead_ogonek E sequence rcaron dead_caron r sequence Rcaron dead_caron R sequence racute dead_acute r sequence Racute dead_acute R sequence tcaron dead_caron t sequence Tcaron dead_caron T sequence tcedilla dead_cedilla t sequence Tcedilla dead_cedilla T sequence zcaron dead_caron z sequence Zcaron dead_caron Z sequence zacute dead_acute z sequence Zacute dead_acute Z sequence zabovedot dead_abovedot z sequence Zabovedot dead_abovedot Z sequence uring dead_abovering u sequence Uring dead_abovering U sequence udoubleacute dead_doubleacute u sequence Udoubleacute dead_doubleacute U sequence odoubleacute dead_doubleacute o sequence Odoubleacute dead_doubleacute O sequence aogonek dead_ogonek a sequence Aogonek dead_ogonek A sequence abreve dead_breve a sequence Abreve dead_breve A sequence scaron dead_caron s sequence Scaron dead_caron S sequence sacute dead_acute s sequence Sacute dead_acute S sequence scedilla dead_cedilla s sequence Scedilla dead_cedilla S sequence dcaron dead_caron d sequence Dcaron dead_caron D sequence gbreve dead_breve g sequence Gbreve dead_breve G sequence lcaron dead_caron l sequence Lcaron dead_caron L sequence lacute dead_acute l sequence Lacute dead_acute L sequence ccaron dead_caron c sequence Ccaron dead_caron C sequence ncaron dead_caron n sequence Ncaron dead_caron N sequence nacute dead_acute n sequence Nacute dead_acute N #Additional sequences end map 0x41B semicolon 0x29 dead_abovering 0x29 shift plus 0x02 1 0x02 shift dead_tilde 0x02 altgr asciitilde 0x02 altgr lcaron 0x03 2 0x03 shift dead_caron 0x03 altgr scaron 0x04 3 0x04 shift dead_circumflex 0x04 altgr ccaron 0x05 4 0x05 shift dead_breve 0x05 altgr tcaron 0x06 5 0x06 shift dead_abovering 0x06 altgr zcaron 0x07 6 0x07 shift dead_ogonek 0x07 altgr yacute 0x08 7 0x08 shift dead_grave 0x08 altgr aacute 0x09 8 0x09 shift dead_abovedot 0x08 altgr iacute 0x0a 9 0x0a shift dead_acute 0x08 altgr eacute 0x0b 0 0x0b shift dead_doubleacute 0x0b altgr equal 0x0c percent 0x0c shift dead_diaeresis 0x0c altgr dead_acute 0x0d dead_caron 0x0d shift dead_cedilla 0x0d altgr backslash 0x10 altgr bar 0x11 altgr EuroSign 0x12 altgr z 0x15 addupper apostrophe 0x19 altgr uacute 0x1a slash 0x1a shift division 0x1a altgr adiaeresis 0x1b parenleft 0x1b shift multiply 0x1b altgr ncaron 0x2b parenright 0x2b shift currency 0x2b altgr dstroke 0x1f altgr Dstroke 0x20 altgr bracketleft 0x21 altgr bracketright 0x22 altgr lstroke 0x25 altgr Lstroke 0x26 altgr ocircumflex 0x27 quotedbl 0x27 shift dollar 0x27 altgr section 0x28 exclam 0x28 shift ssharp 0x28 altgr y 0x2c addupper numbersign 0x2d altgr ampersand 0x2e altgr at 0x2f altgr braceleft 0x30 altgr braceright 0x31 altgr comma 0x33 question 0x33 shift less 0x33 altgr period 0x34 colon 0x34 shift greater 0x34 altgr minus 0x35 underscore 0x35 shift asterisk 0x35 altgr rdesktop-1.8.3/keymaps/sl0000664000770100510440000000436507761153016014325 0ustar hean01hean01# generated from XKB map sl include common map 0x424 exclam 0x02 shift asciitilde 0x02 altgr dead_tilde 0x02 shift altgr quotedbl 0x03 shift dead_caron 0x03 altgr caron 0x03 shift altgr numbersign 0x04 shift asciicircum 0x04 altgr dead_circumflex 0x04 shift altgr dollar 0x05 shift dead_breve 0x05 altgr breve 0x05 shift altgr percent 0x06 shift degree 0x06 altgr dead_abovering 0x06 shift altgr ampersand 0x07 shift dead_ogonek 0x07 altgr ogonek 0x07 shift altgr slash 0x08 shift grave 0x08 altgr dead_grave 0x08 shift altgr parenleft 0x09 shift dead_abovedot 0x09 altgr abovedot 0x09 shift altgr parenright 0x0a shift dead_acute 0x0a altgr equal 0x0b shift dead_doubleacute 0x0b altgr doubleacute 0x0b shift altgr apostrophe 0x0c question 0x0c shift dead_diaeresis 0x0c altgr diaeresis 0x0c shift altgr plus 0x0d asterisk 0x0d shift dead_cedilla 0x0d altgr cedilla 0x0d shift altgr backslash 0x10 altgr Greek_OMEGA 0x10 shift altgr bar 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr z 0x15 addupper leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr scaron 0x1a Scaron 0x1a shift division 0x1a altgr dstroke 0x1b Dstroke 0x1b shift multiply 0x1b altgr dead_macron 0x1b shift altgr ae 0x1e altgr AE 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr bracketleft 0x21 altgr ordfeminine 0x21 shift altgr bracketright 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr lstroke 0x25 altgr Lstroke 0x26 altgr ccaron 0x27 Ccaron 0x27 shift cacute 0x28 Cacute 0x28 shift ssharp 0x28 altgr dead_cedilla 0x29 notsign 0x29 altgr zcaron 0x2b Zcaron 0x2b shift currency 0x2b altgr y 0x2c addupper guillemotleft 0x2c altgr guillemotright 0x2d altgr cent 0x2e altgr copyright 0x2e shift altgr at 0x2f altgr braceleft 0x30 altgr braceright 0x31 altgr section 0x32 altgr masculine 0x32 shift altgr comma 0x33 semicolon 0x33 shift horizconnector 0x33 altgr period 0x34 colon 0x34 shift periodcentered 0x34 altgr minus 0x35 underscore 0x35 shift dead_belowdot 0x35 altgr rdesktop-1.8.3/keymaps/sv0000664000770100510440000000173310274402635014330 0ustar hean01hean01map 0x0000041d include common # # Top row # section 0x29 onehalf 0x29 shift # 1 exclam 0x2 shift # 2 quotedbl 0x3 shift at 0x3 altgr # 3 numbersign 0x4 shift sterling 0x4 altgr # 4 currency 0x5 shift dollar 0x5 altgr # 5 percent 0x6 shift # 6 ampersand 0x7 shift # 7 slash 0x8 shift braceleft 0x8 altgr # 8 parenleft 0x9 shift bracketleft 0x9 altgr # 9 parenright 0xa shift bracketright 0xa altgr # 0 equal 0xb shift braceright 0xb altgr plus 0xc question 0xc shift backslash 0xc altgr dead_acute 0xd dead_grave 0xd shift # # QWERTY first row # EuroSign 0x12 altgr aring 0x1a Aring 0x1a shift dead_diaeresis 0x1b dead_circumflex 0x1b shift dead_tilde 0x1b altgr # # QWERTY second row # odiaeresis 0x27 Odiaeresis 0x27 shift adiaeresis 0x28 Adiaeresis 0x28 shift apostrophe 0x2b asterisk 0x2b shift # # QWERTY third row # less 0x56 greater 0x56 shift bar 0x56 altgr mu 0x32 altgr comma 0x33 semicolon 0x33 shift period 0x34 colon 0x34 shift minus 0x35 underscore 0x35 shift rdesktop-1.8.3/keymaps/th0000664000770100510440000000606307554011737014322 0ustar hean01hean01# generated from XKB map th include common map 0x41e exclam 0x02 shift Thai_lakkhangyao 0x02 altgr plus 0x02 shift altgr at 0x03 shift slash 0x03 altgr Thai_leknung 0x03 shift altgr numbersign 0x04 shift minus 0x04 altgr Thai_leksong 0x04 shift altgr dollar 0x05 shift Thai_phosamphao 0x05 altgr Thai_leksam 0x05 shift altgr percent 0x06 shift Thai_thothung 0x06 altgr Thai_leksi 0x06 shift altgr asciicircum 0x07 shift Thai_sarau 0x07 altgr Thai_sarauu 0x07 shift altgr ampersand 0x08 shift Thai_saraue 0x08 altgr Thai_baht 0x08 shift altgr asterisk 0x09 shift Thai_khokhwai 0x09 altgr Thai_lekha 0x09 shift altgr parenleft 0x0a shift Thai_totao 0x0a altgr Thai_lekhok 0x0a shift altgr parenright 0x0b shift Thai_chochan 0x0b altgr Thai_lekchet 0x0b shift altgr minus 0x0c underscore 0x0c shift Thai_khokhai 0x0c altgr Thai_lekpaet 0x0c shift altgr equal 0x0d plus 0x0d shift Thai_chochang 0x0d altgr Thai_lekkao 0x0d shift altgr Thai_maiyamok 0x10 altgr Thai_leksun 0x10 shift altgr Thai_saraaimaimalai 0x11 altgr quotedbl 0x11 shift altgr Thai_saraam 0x12 altgr Thai_dochada 0x12 shift altgr Thai_phophan 0x13 altgr Thai_thonangmontho 0x13 shift altgr Thai_saraa 0x14 altgr Thai_thothong 0x14 shift altgr Thai_maihanakat 0x15 altgr Thai_nikhahit 0x15 shift altgr Thai_saraii 0x16 altgr Thai_maitri 0x16 shift altgr Thai_rorua 0x17 altgr Thai_nonen 0x17 shift altgr Thai_nonu 0x18 altgr Thai_paiyannoi 0x18 shift altgr Thai_yoyak 0x19 altgr Thai_yoying 0x19 shift altgr bracketleft 0x1a braceleft 0x1a shift Thai_bobaimai 0x1a altgr Thai_thothan 0x1a shift altgr bracketright 0x1b braceright 0x1b shift Thai_loling 0x1b altgr comma 0x1b shift altgr Thai_fofan 0x1e altgr Thai_ru 0x1e shift altgr Thai_hohip 0x1f altgr Thai_khorakhang 0x1f shift altgr Thai_kokai 0x20 altgr Thai_topatak 0x20 shift altgr Thai_dodek 0x21 altgr Thai_sarao 0x21 shift altgr Thai_sarae 0x22 altgr Thai_chochoe 0x22 shift altgr Thai_maitho 0x23 altgr Thai_maitaikhu 0x23 shift altgr Thai_maiek 0x24 altgr Thai_maichattawa 0x24 shift altgr Thai_saraaa 0x25 altgr Thai_sorusi 0x25 shift altgr Thai_sosua 0x26 altgr Thai_sosala 0x26 shift altgr semicolon 0x27 colon 0x27 shift Thai_wowaen 0x27 altgr Thai_soso 0x27 shift altgr apostrophe 0x28 quotedbl 0x28 shift Thai_ngongu 0x28 altgr period 0x28 shift altgr grave 0x29 asciitilde 0x29 shift underscore 0x29 altgr percent 0x29 shift altgr ISO_First_Group 0x2a shift backslash 0x2b bar 0x2b shift Thai_khokhuat 0x2b altgr Thai_khokhon 0x2b shift altgr Thai_phophung 0x2c altgr parenleft 0x2c shift altgr Thai_popla 0x2d altgr parenright 0x2d shift altgr Thai_saraae 0x2e altgr Thai_choching 0x2e shift altgr Thai_oang 0x2f altgr Thai_honokhuk 0x2f shift altgr Thai_sarai 0x30 altgr Thai_phinthu 0x30 shift altgr Thai_sarauee 0x31 altgr Thai_thanthakhat 0x31 shift altgr Thai_thothahan 0x32 altgr question 0x32 shift altgr comma 0x33 less 0x33 shift Thai_moma 0x33 altgr Thai_thophuthao 0x33 shift altgr period 0x34 greater 0x34 shift Thai_saraaimaimuan 0x34 altgr Thai_lochula 0x34 shift altgr slash 0x35 question 0x35 shift Thai_fofa 0x35 altgr Thai_lu 0x35 shift altgr ISO_Last_Group 0x36 shift rdesktop-1.8.3/keymaps/tr0000664000770100510440000000426310775616311014332 0ustar hean01hean01# rdesktop Turkish Q Keyboard Layout # # Modified by Umit Oztosun 20040328 # # Modified from the original mapping file provided with rdesktop 1.3.1. # This version works correctly with the right X settings. include common map 0x41f # First row quotedbl 0x29 eacute 0x29 shift backslash 0x29 altgr exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr apostrophe 0x03 shift sterling 0x03 altgr twosuperior 0x03 shift altgr dead_circumflex 0x04 shift numbersign 0x04 altgr threesuperior 0x04 shift altgr plus 0x05 shift dollar 0x05 altgr onequarter 0x05 shift altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr ampersand 0x07 shift threequarters 0x07 altgr slash 0x08 shift braceleft 0x08 altgr parenleft 0x09 shift bracketleft 0x09 altgr parenright 0x0a shift bracketright 0x0a altgr plusminus 0x0a shift altgr equal 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr asterisk 0x0c question 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr minus 0x0d underscore 0x0d shift division 0x0d altgr at 0x10 altgr EuroSign 0x12 altgr trademark 0x14 altgr ucircumflex 0x16 altgr Ucircumflex 0x16 shift altgr idotless 0x17 I 0x17 shift icircumflex 0x17 altgr Icircumflex 0x17 altgr shift ocircumflex 0x18 altgr Ocircumflex 0x18 shift altgr gbreve 0x1a Gbreve 0x1a shift udiaeresis 0x1b Udiaeresis 0x1b shift asciitilde 0x1b altgr dead_macron 0x1b shift altgr comma 0x2b semicolon 0x2b shift grave 0x2b altgr dead_grave 0x2b altgr shift # Second row acircumflex 0x1e altgr Acircumflex 0x1e shift altgr section 0x1f altgr ordfeminine 0x21 altgr scedilla 0x27 Scedilla 0x27 shift acute 0x27 altgr dead_acute 0x27 shift altgr i 0x28 Iabovedot 0x28 shift dead_caron 0x28 shift altgr less 0x56 greater 0x56 shift bar 0x56 altgr brokenbar 0x56 shift altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr masculine 0x32 shift altgr odiaeresis 0x33 Odiaeresis 0x33 shift multiply 0x33 altgr ccedilla 0x34 Ccedilla 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr period 0x35 colon 0x35 shift dead_abovedot 0x35 altgr dead_abovedot 0x35 shift altgr rdesktop-1.8.3/keymaps/de-ch0000664000770100510440000000475610054357706014674 0ustar hean01hean01# rdesktop Swiss-German (de-ch) keymap file # 2003-06-03 by noldi@tristar.ch # include common map 0x00000807 # # Scan Code 1 section 0x29 degree 0x29 shift notsign 0x29 altgr inhibit # # Scan Code 2 plus 0x2 shift brokenbar 0x02 altgr # # Scan Code 3 quotedbl 0x03 shift at 0x03 altgr # # Scan Code 4 asterisk 0x04 shift numbersign 0x04 altgr # # Scan Code 5 ccedilla 0x05 shift onequarter 0x05 altgr inhibit # # Scan Code 6 percent 0x06 shift onehalf 0x06 altgr inhibit # # Scan Code 7 ampersand 0x07 shift notsign 0x07 altgr # # Scan Code 8 slash 0x08 shift bar 0x08 altgr # # Scan Code 9 parenleft 0x09 shift cent 0x09 altgr # # Scan Code 10 parenright 0x0a shift # # Scan Code 11 equal 0x0b shift braceright 0x0b altgr inhibit # # Scan Code 12 apostrophe 0x0c question 0x0c shift dead_acute 0x0c altgr # # Scan Code 13 dead_circumflex 0x0d dead_grave 0x0d shift dead_tilde 0x0d altgr # # Scan Code 19 EuroSign 0x12 altgr # # Scan Code 22 z 0x15 addupper # # Scan Code 27 udiaeresis 0x1a egrave 0x1a shift bracketleft 0x1a altgr # # Scan Code 28 dead_diaeresis 0x1b exclam 0x1b shift bracketright 0x1b altgr # # Scan Code 40 odiaeresis 0x27 eacute 0x27 shift # # Scan Code 41 adiaeresis 0x28 agrave 0x28 shift braceleft 0x28 altgr # # Scan Code 42 (only on international keyboards) dollar 0x2b sterling 0x2b shift braceright 0x2b altgr # # Scan Code 45 (only on international keyboards) backslash 0x56 altgr # # Scan Code 46 y 0x2c addupper # # Scan Code 53 comma 0x33 semicolon 0x33 shift # # Scan Code 54 period 0x34 colon 0x34 shift # # Scan Code 55 minus 0x35 underscore 0x35 shift # # Suppress Windows unsupported AltGr keys # # Scan Code 17 paragraph 0x10 altgr inhibit # # Scan Code 21 tslash 0x14 altgr inhibit # # Scan Code 22 leftarrow 0x15 altgr inhibit # # Scan Code 23 downarrow 0x16 altgr inhibit # # Scan Code 24 rightarrow 0x17 altgr inhibit # # Scan Code 25 oslash 0x18 altgr inhibit # # Scan Code 26 thorn 0x19 altgr inhibit # # Scan Code 31 ae 0x1e altgr inhibit # # Scan Code 32 ssharp 0x1f altgr inhibit # # Scan Code 33 eth 0x20 altgr inhibit # # Scan Code 34 dstroke 0x21 altgr inhibit # # Scan Code 35 eng 0x22 altgr inhibit # # Scan Code 36 hstroke 0x23 altgr inhibit # # Scan Code 38 kra 0x25 altgr inhibit # # Scan Code 39 lstroke 0x26 altgr inhibit # # Scan Code 46 guillemotleft 0x2c altgr inhibit # # Scan Code 47 guillemotright 0x2d altgr inhibit # # Scan Code 49 leftdoublequotemark 0x2f altgr inhibit # # Scan Code 50 rightdoublequotemark 0x30 altgr inhibit # # Scan Code 52 mu 0x32 altgr inhibit rdesktop-1.8.3/keymaps/en-dv0000664000770100510440000000564010325651545014715 0ustar hean01hean01# American Dvorak map 0x10409 # Note: we are not including the common section include modifiers # # Top row # 1 0x2 2 0x3 3 0x4 4 0x5 5 0x6 6 0x7 7 0x8 8 0x9 9 0xa 0 0xb BackSpace 0xe # # QWERTY first row # QWERTY: # q w e r t y u i o p # Dvorak: # ' , . p y f g c r l Tab 0xf localstate ISO_Left_Tab 0xf shift q 0x2d addupper w 0x33 addupper e 0x20 addupper r 0x18 addupper t 0x25 addupper y 0x14 addupper u 0x21 addupper i 0x22 addupper o 0x1f addupper p 0x13 addupper # # QWERTY second row # QUERTY: # a s d f g h j k l # Dvorak: # a o e u i d h t n a 0x1e addupper s 0x27 addupper d 0x23 addupper f 0x15 addupper g 0x16 addupper h 0x24 addupper j 0x2e addupper k 0x2f addupper l 0x19 addupper Return 0x1c localstate # # QWERTY third row # QUERTY: # z x c v b n m # Dvorak: # ; q j k x b m z 0x35 addupper x 0x30 addupper c 0x17 addupper v 0x34 addupper b 0x31 addupper n 0x26 addupper m 0x32 addupper space 0x39 localstate less 0x56 greater 0x56 shift bar 0x56 altgr brokenbar 0x56 shift altgr # # Esc and Function keys # Escape 0x1 localstate F1 0x3b localstate F2 0x3c localstate F3 0x3d localstate F4 0x3e localstate F5 0x3f localstate F6 0x40 localstate F7 0x41 localstate F8 0x42 localstate F9 0x43 localstate F10 0x44 localstate F11 0x57 localstate SunF36 0x57 localstate F12 0x58 localstate SunF37 0x58 localstate # Printscreen, Scrollock and Pause # Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37), # but (0xe0, 0x37) seems to work. Print 0xb7 localstate Sys_Req 0xb7 localstate Execute 0xb7 localstate F22 0xb7 localstate Scroll_Lock 0x46 F23 0x46 # # Insert - PgDown # Insert 0xd2 localstate Delete 0xd3 localstate Home 0xc7 localstate End 0xcf localstate Page_Up 0xc9 localstate Page_Down 0xd1 localstate # # Arrow keys # Left 0xcb localstate Up 0xc8 localstate Down 0xd0 localstate Right 0xcd localstate # # Numpad # Num_Lock 0x45 KP_Divide 0xb5 KP_Multiply 0x37 KP_Subtract 0x4a KP_Add 0x4e KP_Enter 0x9c KP_Decimal 0x53 numlock KP_Separator 0x53 numlock KP_Delete 0x53 KP_0 0x52 numlock KP_Insert 0x52 KP_1 0x4f numlock KP_End 0x4f KP_2 0x50 numlock KP_Down 0x50 KP_3 0x51 numlock KP_Next 0x51 KP_4 0x4b numlock KP_Left 0x4b KP_5 0x4c numlock KP_Begin 0x4c KP_6 0x4d numlock KP_Right 0x4d KP_7 0x47 numlock KP_Home 0x47 KP_8 0x48 numlock KP_Up 0x48 KP_9 0x49 numlock KP_Prior 0x49 # # Inhibited keys # Caps_Lock 0x0 inhibit Multi_key 0x0 inhibit exclam 0x02 shift at 0x03 shift numbersign 0x04 shift dollar 0x05 shift percent 0x06 shift asciicircum 0x07 shift ampersand 0x08 shift asterisk 0x09 shift parenleft 0x0a shift parenright 0x0b shift minus 0x28 underscore 0x28 shift equal 0x1b plus 0x1b shift bracketleft 0x0c braceleft 0x0c shift bracketright 0x0d braceright 0x0d shift semicolon 0x2c colon 0x2c shift apostrophe 0x10 quotedbl 0x10 shift grave 0x29 asciitilde 0x29 shift backslash 0x2b bar 0x2b shift comma 0x11 less 0x11 shift period 0x12 greater 0x12 shift slash 0x1a question 0x1a shift rdesktop-1.8.3/keymaps/en-gb0000664000770100510440000000502507613324423014667 0ustar hean01hean01# generated from XKB map gb include common map 0x809 exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr quotedbl 0x03 shift twosuperior 0x03 altgr oneeighth 0x03 shift altgr sterling 0x04 shift threesuperior 0x04 altgr dollar 0x05 shift EuroSign 0x05 altgr percent 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr asciicircum 0x07 shift threequarters 0x07 altgr fiveeighths 0x07 shift altgr ampersand 0x08 shift braceleft 0x08 altgr seveneighths 0x08 shift altgr asterisk 0x09 shift bracketleft 0x09 altgr trademark 0x09 shift altgr parenleft 0x0a shift bracketright 0x0a altgr plusminus 0x0a shift altgr parenright 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr minus 0x0c underscore 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr equal 0x0d plus 0x0d shift dead_cedilla 0x0d altgr dead_ogonek 0x0d shift altgr at 0x10 altgr Greek_OMEGA 0x10 shift altgr lstroke 0x11 altgr Lstroke 0x11 shift altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr bracketleft 0x1a braceleft 0x1a shift dead_diaeresis 0x1a altgr dead_abovering 0x1a shift altgr bracketright 0x1b braceright 0x1b shift dead_tilde 0x1b altgr dead_macron 0x1b shift altgr ae 0x1e altgr AE 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr semicolon 0x27 colon 0x27 shift dead_acute 0x27 altgr dead_doubleacute 0x27 shift altgr apostrophe 0x28 at 0x28 shift dead_circumflex 0x28 altgr dead_caron 0x28 shift altgr grave 0x29 notsign 0x29 shift bar 0x29 altgr numbersign 0x2b asciitilde 0x2b shift dead_grave 0x2b altgr dead_breve 0x2b shift altgr guillemotleft 0x2c altgr less 0x2c shift altgr guillemotright 0x2d altgr greater 0x2d shift altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr rightdoublequotemark 0x30 altgr mu 0x32 altgr masculine 0x32 shift altgr comma 0x33 less 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr period 0x34 greater 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr slash 0x35 question 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr backslash 0x56 bar 0x56 shift rdesktop-1.8.3/keymaps/en-us0000664000770100510440000000114107555726423014734 0ustar hean01hean01# generated from XKB map us include common map 0x409 exclam 0x02 shift at 0x03 shift numbersign 0x04 shift dollar 0x05 shift percent 0x06 shift asciicircum 0x07 shift ampersand 0x08 shift asterisk 0x09 shift parenleft 0x0a shift parenright 0x0b shift minus 0x0c underscore 0x0c shift equal 0x0d plus 0x0d shift bracketleft 0x1a braceleft 0x1a shift bracketright 0x1b braceright 0x1b shift semicolon 0x27 colon 0x27 shift apostrophe 0x28 quotedbl 0x28 shift grave 0x29 asciitilde 0x29 shift backslash 0x2b bar 0x2b shift comma 0x33 less 0x33 shift period 0x34 greater 0x34 shift slash 0x35 question 0x35 shift rdesktop-1.8.3/keymaps/fr-be0000664000770100510440000000526010074574503014674 0ustar hean01hean01# generated from XKB map be include common map 0x80c ampersand 0x02 1 0x02 shift bar 0x02 altgr exclamdown 0x02 shift altgr eacute 0x03 2 0x03 shift at 0x03 altgr oneeighth 0x03 shift altgr quotedbl 0x04 3 0x04 shift numbersign 0x04 altgr sterling 0x04 shift altgr apostrophe 0x05 4 0x05 shift onequarter 0x05 altgr dollar 0x05 shift altgr parenleft 0x06 5 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr section 0x07 6 0x07 shift asciicircum 0x07 altgr fiveeighths 0x07 shift altgr egrave 0x08 7 0x08 shift braceleft 0x08 altgr seveneighths 0x08 shift altgr exclam 0x09 8 0x09 shift bracketleft 0x09 altgr trademark 0x09 shift altgr ccedilla 0x0a 9 0x0a shift braceleft 0x0a altgr plusminus 0x0a shift altgr agrave 0x0b 0 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr parenright 0x0c degree 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr minus 0x0d underscore 0x0d shift dead_cedilla 0x0d altgr dead_ogonek 0x0d shift altgr a 0x10 addupper Greek_OMEGA 0x10 shift altgr z 0x11 addupper lstroke 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr cent 0x12 shift altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr dead_circumflex 0x1a dead_diaeresis 0x1a shift bracketleft 0x1a altgr dead_abovering 0x1a shift altgr dollar 0x1b asterisk 0x1b shift bracketright 0x1b altgr dead_macron 0x1b shift altgr q 0x1e addupper ae 0x1e altgr AE 0x1e shift altgr ssharp 0x1f altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr m 0x27 addupper dead_acute 0x27 altgr dead_doubleacute 0x27 shift altgr ugrave 0x28 percent 0x28 shift dead_acute 0x28 altgr dead_caron 0x28 shift altgr twosuperior 0x29 threesuperior 0x29 shift notsign 0x29 altgr mu 0x2b sterling 0x2b shift dead_grave 0x2b altgr dead_breve 0x2b shift altgr w 0x2c addupper guillemotleft 0x2c altgr guillemotright 0x2d altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr comma 0x32 question 0x32 shift dead_cedilla 0x32 altgr masculine 0x32 shift altgr semicolon 0x33 period 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr colon 0x34 slash 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr equal 0x35 plus 0x35 shift dead_tilde 0x35 altgr dead_abovedot 0x35 shift altgr backslash 0x56 altgr rdesktop-1.8.3/keymaps/fr-ca0000664000770100510440000000173110775615432014675 0ustar hean01hean01# Canadian French # By Simon Germain include common map 0xc0c backslash 0x29 altgr plusminus 0x2 altgr at 0x3 altgr sterling 0x4 altgr cent 0x5 altgr currency 0x6 altgr notsign 0x7 altgr bar 0x29 shift twosuperior 0x9 altgr threesuperior 0xa altgr onequarter 0xb altgr onehalf 0xc altgr threequarters 0xd altgr section 0x18 altgr paragraph 0x19 altgr bracketleft 0x1a altgr bracketright 0x1b altgr asciitilde 0x27 altgr braceleft 0x28 altgr braceright 0x2b altgr less 0x2b greater 0x2b shift guillemotleft 0x56 guillemotright 0x56 shift degree 0x56 altgr mu 0x32 altgr eacute 0x35 dead_acute 0x35 altgr dead_grave 0x28 dead_circumflex 0x1a dead_circumflex 0x1a shift dead_cedilla 0x1b dead_diaeresis 0x1b shift exclam 0x2 shift quotedbl 0x3 shift comma 0x33 apostrophe 0x33 shift period 0x34 shift slash 0x4 shift dollar 0x5 shift percent 0x6 shift question 0x7 shift ampersand 0x8 shift asterisk 0x9 shift parenleft 0xa shift parenright 0xb shift underscore 0xc shift plus 0xd shift rdesktop-1.8.3/keymaps/fr-ch0000664000770100510440000000473010205673041014672 0ustar hean01hean01# rdesktop suisse-french keymap file # #map 0x00000807 map 0x0000100C include common # # Scan Code 1 section 0x29 degree 0x29 shift notsign 0x29 altgr inhibit # # Scan Code 2 plus 0x2 shift brokenbar 0x02 altgr # # Scan Code 3 quotedbl 0x03 shift at 0x03 altgr # # Scan Code 4 asterisk 0x04 shift numbersign 0x04 altgr # # Scan Code 5 ccedilla 0x05 shift onequarter 0x05 altgr inhibit # # Scan Code 6 percent 0x06 shift onehalf 0x06 altgr inhibit # # Scan Code 7 ampersand 0x07 shift notsign 0x07 altgr # # Scan Code 8 slash 0x08 shift bar 0x08 altgr # # Scan Code 9 parenleft 0x09 shift cent 0x09 altgr # # Scan Code 10 parenright 0x0a shift # # Scan Code 11 equal 0x0b shift braceright 0x0b altgr inhibit # # Scan Code 12 apostrophe 0x0c question 0x0c shift dead_acute 0x0c altgr # # Scan Code 13 dead_circumflex 0x0d dead_grave 0x0d shift dead_tilde 0x0d altgr # # Scan Code 19 EuroSign 0x12 altgr # # Scan Code 22 z 0x15 addupper # # Scan Code 27 udiaeresis 0x1a shift egrave 0x1a bracketleft 0x1a altgr # # Scan Code 28 dead_diaeresis 0x1b exclam 0x1b shift bracketright 0x1b altgr # # Scan Code 40 odiaeresis 0x27 shift eacute 0x27 # # Scan Code 41 adiaeresis 0x28 shift agrave 0x28 braceleft 0x28 altgr # # Scan Code 42 (only on international keyboards) dollar 0x2b sterling 0x2b shift braceright 0x2b altgr # # Scan Code 45 (only on international keyboards) backslash 0x56 altgr # # Scan Code 46 y 0x2c addupper # # Scan Code 53 comma 0x33 semicolon 0x33 shift # # Scan Code 54 period 0x34 colon 0x34 shift # # Scan Code 55 minus 0x35 underscore 0x35 shift # # Suppress Windows unsupported AltGr keys # # Scan Code 17 paragraph 0x10 altgr inhibit # # Scan Code 21 tslash 0x14 altgr inhibit # # Scan Code 22 leftarrow 0x15 altgr inhibit # # Scan Code 23 downarrow 0x16 altgr inhibit # # Scan Code 24 rightarrow 0x17 altgr inhibit # # Scan Code 25 oslash 0x18 altgr inhibit # # Scan Code 26 thorn 0x19 altgr inhibit # # Scan Code 31 ae 0x1e altgr inhibit # # Scan Code 32 ssharp 0x1f altgr inhibit # # Scan Code 33 eth 0x20 altgr inhibit # # Scan Code 34 dstroke 0x21 altgr inhibit # # Scan Code 35 eng 0x22 altgr inhibit # # Scan Code 36 hstroke 0x23 altgr inhibit # # Scan Code 38 kra 0x25 altgr inhibit # # Scan Code 39 lstroke 0x26 altgr inhibit # # Scan Code 46 guillemotleft 0x2c altgr inhibit # # Scan Code 47 guillemotright 0x2d altgr inhibit # # Scan Code 49 leftdoublequotemark 0x2f altgr inhibit # # Scan Code 50 rightdoublequotemark 0x30 altgr inhibit # # Scan Code 52 mu 0x32 altgr inhibit rdesktop-1.8.3/keymaps/nl-be0000664000770100510440000000552610273735553014710 0ustar hean01hean01# Dutch (Belgium) map 0x813 include common ampersand 0x02 1 0x02 shift bar 0x02 altgr exclamdown 0x02 shift altgr eacute 0x03 2 0x03 shift at 0x03 altgr oneeighth 0x03 shift altgr quotedbl 0x04 3 0x04 shift numbersign 0x04 altgr sterling 0x04 shift altgr apostrophe 0x05 4 0x05 shift onequarter 0x05 altgr dollar 0x05 shift altgr parenleft 0x06 5 0x06 shift onehalf 0x06 altgr threeeighths 0x06 shift altgr section 0x07 6 0x07 shift asciicircum 0x07 altgr fiveeighths 0x07 shift altgr egrave 0x08 7 0x08 shift braceleft 0x08 altgr seveneighths 0x08 shift altgr exclam 0x09 8 0x09 shift bracketleft 0x09 altgr trademark 0x09 shift altgr ccedilla 0x0a 9 0x0a shift braceleft 0x0a altgr plusminus 0x0a shift altgr agrave 0x0b 0 0x0b shift braceright 0x0b altgr degree 0x0b shift altgr parenright 0x0c degree 0x0c shift backslash 0x0c altgr questiondown 0x0c shift altgr minus 0x0d underscore 0x0d shift dead_cedilla 0x0d altgr dead_ogonek 0x0d shift altgr a 0x10 addupper # at 0x10 altgr Greek_OMEGA 0x10 shift altgr z 0x11 addupper lstroke 0x11 altgr Lstroke 0x11 shift altgr EuroSign 0x12 altgr cent 0x12 shift altgr paragraph 0x13 altgr registered 0x13 shift altgr tslash 0x14 altgr Tslash 0x14 shift altgr leftarrow 0x15 altgr yen 0x15 shift altgr downarrow 0x16 altgr uparrow 0x16 shift altgr rightarrow 0x17 altgr idotless 0x17 shift altgr oslash 0x18 altgr Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr dead_circumflex 0x1a dead_diaeresis 0x1a shift bracketleft 0x1a altgr dead_abovering 0x1a shift altgr dollar 0x1b asterisk 0x1b shift bracketright 0x1b altgr dead_macron 0x1b shift altgr q 0x1e addupper ae 0x1e altgr AE 0x1e shift altgr ssharp 0x1f altgr section 0x1f shift altgr eth 0x20 altgr ETH 0x20 shift altgr dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr ENG 0x22 shift altgr hstroke 0x23 altgr Hstroke 0x23 shift altgr kra 0x25 altgr # ampersand 0x25 shift altgr lstroke 0x26 altgr Lstroke 0x26 shift altgr m 0x27 addupper dead_acute 0x27 altgr dead_doubleacute 0x27 shift altgr ugrave 0x28 percent 0x28 shift dead_acute 0x28 altgr dead_caron 0x28 shift altgr twosuperior 0x29 threesuperior 0x29 shift notsign 0x29 altgr mu 0x2b sterling 0x2b shift dead_grave 0x2b altgr dead_breve 0x2b shift altgr w 0x2c addupper guillemotleft 0x2c altgr less 0x2c shift altgr guillemotright 0x2d altgr greater 0x2d shift altgr cent 0x2e altgr copyright 0x2e shift altgr leftdoublequotemark 0x2f altgr grave 0x2f shift altgr rightdoublequotemark 0x30 altgr # apostrophe 0x30 shift altgr comma 0x32 question 0x32 shift dead_cedilla 0x32 altgr masculine 0x32 shift altgr semicolon 0x33 period 0x33 shift horizconnector 0x33 altgr multiply 0x33 shift altgr colon 0x34 slash 0x34 shift periodcentered 0x34 altgr division 0x34 shift altgr equal 0x35 plus 0x35 shift dead_tilde 0x35 altgr dead_abovedot 0x35 shift altgr backslash 0x56 altgr less 0x56 greater 0x56 shift rdesktop-1.8.3/keymaps/pt-br0000664000770100510440000000251207765064025014730 0ustar hean01hean01# generated from XKB map br include common map 0x416 exclam 0x02 shift onesuperior 0x02 altgr exclamdown 0x02 shift altgr at 0x03 shift twosuperior 0x03 altgr onehalf 0x03 shift altgr numbersign 0x04 shift threesuperior 0x04 altgr threequarters 0x04 shift altgr dollar 0x05 shift sterling 0x05 altgr onequarter 0x05 shift altgr percent 0x06 shift cent 0x06 altgr dead_diaeresis 0x07 shift notsign 0x07 altgr diaeresis 0x07 shift altgr ampersand 0x08 shift braceleft 0x08 altgr asterisk 0x09 shift bracketleft 0x09 altgr parenleft 0x0a shift bracketright 0x0a altgr parenright 0x0b shift braceright 0x0b altgr minus 0x0c underscore 0x0c shift backslash 0x0c altgr equal 0x0d plus 0x0d shift section 0x0d altgr EuroSign 0x12 altgr registered 0x13 altgr dead_acute 0x1a dead_grave 0x1a shift acute 0x1a altgr grave 0x1a shift altgr bracketleft 0x1b braceleft 0x1b shift ordfeminine 0x1b altgr ccedilla 0x27 Ccedilla 0x27 shift dead_tilde 0x28 dead_circumflex 0x28 shift asciitilde 0x28 altgr asciicircum 0x28 shift altgr apostrophe 0x29 quotedbl 0x29 shift bracketright 0x2b braceright 0x2b shift masculine 0x2b altgr copyright 0x2e altgr mu 0x32 altgr comma 0x33 less 0x33 shift period 0x34 greater 0x34 shift semicolon 0x35 colon 0x35 shift comma 0x53 numlock backslash 0x56 bar 0x56 shift slash 0x73 question 0x73 shift degree 0x73 altgr KP_Decimal 0x34 rdesktop-1.8.3/keymaps/common0000664000770100510440000001064210421176003015156 0ustar hean01hean01include modifiers # # Top row # 1 0x2 2 0x3 3 0x4 4 0x5 5 0x6 6 0x7 7 0x8 8 0x9 9 0xa 0 0xb BackSpace 0xe # # QWERTY first row # Tab 0xf localstate ISO_Left_Tab 0xf shift q 0x10 addupper w 0x11 addupper e 0x12 addupper sequence egrave dead_grave e sequence Egrave dead_grave E sequence eacute dead_acute e sequence Eacute dead_acute E sequence ecircumflex dead_circumflex e sequence Ecircumflex dead_circumflex E sequence ediaeresis dead_diaeresis e sequence Ediaeresis dead_diaeresis E r 0x13 addupper t 0x14 addupper y 0x15 addupper sequence ygrave dead_grave y sequence Ygrave dead_grave Y sequence yacute dead_acute y sequence Yacute dead_acute Y sequence ycircumflex dead_circumflex y sequence Ycircumflex dead_circumflex Y sequence ydiaeresis dead_diaeresis y sequence Ydiaeresis dead_diaeresis Y u 0x16 addupper sequence ugrave dead_grave u sequence Ugrave dead_grave U sequence uacute dead_acute u sequence Uacute dead_acute U sequence ucircumflex dead_circumflex u sequence Ucircumflex dead_circumflex U sequence udiaeresis dead_diaeresis u sequence Udiaeresis dead_diaeresis U i 0x17 addupper sequence igrave dead_grave i sequence Igrave dead_grave I sequence iacute dead_acute i sequence Iacute dead_acute I sequence icircumflex dead_circumflex i sequence Icircumflex dead_circumflex I sequence idiaeresis dead_diaeresis i sequence Idiaeresis dead_diaeresis I o 0x18 addupper sequence ograve dead_grave o sequence Ograve dead_grave O sequence oacute dead_acute o sequence Oacute dead_acute O sequence ocircumflex dead_circumflex o sequence Ocircumflex dead_circumflex O sequence odiaeresis dead_diaeresis o sequence Odiaeresis dead_diaeresis O sequence otilde dead_tilde o sequence Otilde dead_tilde O p 0x19 addupper # # QWERTY second row # a 0x1e addupper sequence agrave dead_grave a sequence Agrave dead_grave A sequence aacute dead_acute a sequence Aacute dead_acute A sequence acircumflex dead_circumflex a sequence Acircumflex dead_circumflex A sequence adiaeresis dead_diaeresis a sequence Adiaeresis dead_diaeresis A sequence aring dead_abovering a sequence Aring dead_abovering A sequence atilde dead_tilde a sequence Atilde dead_tilde A s 0x1f addupper d 0x20 addupper f 0x21 addupper g 0x22 addupper h 0x23 addupper j 0x24 addupper k 0x25 addupper l 0x26 addupper Return 0x1c localstate # # QWERTY third row # z 0x2c addupper x 0x2d addupper c 0x2e addupper sequence ccedilla dead_cedilla c sequence Ccedilla dead_cedilla C v 0x2f addupper b 0x30 addupper n 0x31 addupper sequence ntilde dead_tilde n sequence Ntilde dead_tilde N m 0x32 addupper space 0x39 localstate less 0x56 greater 0x56 shift bar 0x56 altgr brokenbar 0x56 shift altgr # # Translations for some other dead keys # sequence asciitilde dead_tilde space sequence diaeresis dead_diaeresis space sequence asciicircum dead_circumflex space sequence apostrophe dead_acute space sequence grave dead_grave space sequence acute dead_acute space # # Esc and Function keys # Escape 0x1 localstate F1 0x3b localstate F2 0x3c localstate F3 0x3d localstate F4 0x3e localstate F5 0x3f localstate F6 0x40 localstate F7 0x41 localstate F8 0x42 localstate F9 0x43 localstate F10 0x44 localstate F11 0x57 localstate SunF36 0x57 localstate F12 0x58 localstate SunF37 0x58 localstate # Printscreen, Scrollock and Pause # Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37), # but (0xe0, 0x37) seems to work. Print 0xb7 localstate Sys_Req 0xb7 localstate Execute 0xb7 localstate F22 0xb7 localstate Scroll_Lock 0x46 F23 0x46 # # Insert - PgDown # Insert 0xd2 localstate Delete 0xd3 localstate Home 0xc7 localstate End 0xcf localstate Page_Up 0xc9 localstate Page_Down 0xd1 localstate # # Arrow keys # Left 0xcb localstate Up 0xc8 localstate Down 0xd0 localstate Right 0xcd localstate # # Numpad # Num_Lock 0x45 KP_Divide 0xb5 localstate KP_Multiply 0x37 localstate KP_Subtract 0x4a localstate KP_Add 0x4e localstate KP_Enter 0x9c localstate KP_Decimal 0x53 numlock KP_Separator 0x53 numlock KP_Delete 0x53 KP_0 0x52 numlock KP_Insert 0x52 localstate KP_1 0x4f numlock KP_End 0x4f localstate KP_2 0x50 numlock KP_Down 0x50 localstate KP_3 0x51 numlock KP_Next 0x51 localstate KP_4 0x4b numlock KP_Left 0x4b localstate KP_5 0x4c numlock KP_Begin 0x4c localstate KP_6 0x4d numlock KP_Right 0x4d localstate KP_7 0x47 numlock KP_Home 0x47 localstate KP_8 0x48 numlock KP_Up 0x48 localstate KP_9 0x49 numlock KP_Prior 0x49 localstate # # Inhibited keys # Caps_Lock 0x0 inhibit Multi_key 0x0 inhibit rdesktop-1.8.3/keymaps/modifiers0000664000770100510440000000050110057033672015651 0ustar hean01hean01Shift_R 0x36 Shift_L 0x2a Alt_R 0xb8 Mode_switch 0xb8 ISO_Level3_Shift 0xb8 Alt_L 0x38 Control_R 0x9d Control_L 0x1d # Translate Meta, Super and Hyper to Windows keys. # This is hardcoded. See documentation for details. # Translate Menu to the Windows Application key. # This one does not work either. Menu 0xdd rdesktop-1.8.3/keymaps/convert-map0000775000770100510440000000343411640622776016146 0ustar hean01hean01#!/usr/bin/env python2 # -*-Python-*- # # Copyright 2001 Peter Åstrand for Cendio AB # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # 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. import sys def main(): f = open(sys.argv[1]) while 1: line = f.readline() if not line: break if line.startswith("#") or line.startswith("include"): print line, continue fields = line.split() if line.startswith("map"): print "map 0x%s" % fields[1] continue scancode = fields[0] for pos in range(1, len(fields)): keysym = fields[pos] if pos == 1: modifiers = "" elif pos == 2: modifiers = "shift" elif pos == 3: modifiers = "altgr" elif pos == 4: modifiers = "shift altgr" else: raise("Invalid line: %s" % line) print "%s 0x%s %s" % (keysym, scancode, modifiers) if __name__ == "__main__": if len(sys.argv) < 2: print "Convert old-style keymaps to new style" print "Usage: %s " % sys.argv[0] sys.exit(1) else: main() rdesktop-1.8.3/doc/HACKING0000664000770100510440000000236710764006640014044 0ustar hean01hean01 Code style / indentation ------------------------ The file indent-all.sh contains information about the current code style. Run this script before commits. Variable argument macros ------------------------ Variable argument macros are non-portable in general, and should be avoided. Either use a second set of parentheses like DEBUG, or create a variable argument function like error. Structure --------- The core protocol stack should be system-independent (i.e. ANSI C89 only) so that it is easy to port. This currently applies to the following files: bitmap.c licence.c orders.c rdp.c rdp5.c cache.c iso.c mcs.c secure.c mppc.c channels.c rdesktop.c Compiler support ---------------- The source code should be compatible with ANSI C89. One exception is the SeamlessRDP ServerEXE and ClientDLL, which should be compatible with ANSI C99. RDP resources ------------- http://dev.remotenetworktechnology.com/refdata.htm Checking for out of memory conditions ------------------------------------- Try to handle out of memory conditions gracefully. Use the xmalloc routines from rdesktop.c, instead of calling malloc manually. Also, remember that several Xlib functions can return NULL. This includes XGetImage. Use exit_if_null to verify returned pointers. rdesktop-1.8.3/doc/AUTHORS0000664000770100510440000000136711551305002014111 0ustar hean01hean01This is an attempt at a list of people who have made significant contributions to the code. If you have been unintentionally omitted please let one of the team members know. Alexi Volkov Erik Forsberg GuoJunBo Henrik Andersson for Cendio AB Hugo Trippaers Jay Sorg Jeremy Meng Jeroen Meijer Matrox Graphics Inc. Matthew Chapman Michael Gernoth Michal Mihalik Norbert Federa Peter Astrand for Cendio AB Peter Kallden Pierre Ossman for Cendio AB rdesktop-1.8.3/doc/TODO0000664000770100510440000000442710772213253013543 0ustar hean01hean01* General * Rework main loop to a generic event handler (i.e. move select() to the top of the stack, not the end). Also means rewriting the connect procedure as a state machine. * Stop using static objects for packets and make it more clear when it is in use (explicit allocation and free). * Clipboard: * Support other data types than plain text. * Conversion between different character sets. * Drive Redirection: * Real support for file locking * Handle reconnections correctly. * Various deficiencies; see FIXMEs in source code. * Serial Port Redirection: * More testing needed. * Printer Redirection: * More testing needed. * Keymapping: * Sound redirection * Use timestamps in audio packets. * Add resampling to supported samplerates of audio-hardware. * Lower CPU-usage with an audio thread. * Smartcard redirection * Merge patches currently implementing sc-redirection. * Miscellaneous * Clean up header files. The current "proto.h" and "xproto.h" is far from optimal. * Go through the many trackers (bugs/patches/RFEs) at SourceForge. * More fancy homepage. * Enhance documentation. Write a FAQ. * SeamlessRDP mode * Add a client to server message for starting additional applications. * Support cmd.exe. * Support for Input Contexts. * Enhanced support for WM_DELETE_WINDOW: Instead of terminating rdesktop, close the window on the server side. * Systray support. * Better support for non-EWMH window managers. * Support for non-rectangular windows. * The focus handling of menus is a bit crude. * Support for sending focus information from client to server. * Implement something similiar to explhook.dll - support for running explorer.exe in non-shell mode. * Better compatibility with Task Manager. * XINERAMA support. * When enumerating windows, make sure to send info about windows that are transient for other windows after the referred window. * We support topmost windows at creating time, but we do not detect when this property is added or removed. This can be verified with task manager, which has an "Always on top" option. * Window icons are not set when reconnecting. get_icon/update_icon needs to be called from enum_cb. rdesktop-1.8.3/doc/ChangeLog0000664000770100510440000001753412424672330014631 0ustar hean01hean01rdesktop (1.8.3) * Added a persistent mode used with SeamlessRDP * Added US international keyboard layout with dead keys * Code cleanup to match specifications, use constants defined instead of magic numbers, remove of dead code * Fix regression with failed connection and a invalid licensing message, introduced in 1.8.2 * Fix issue with Non ASCII user / password when using CredSSP * Fix issues using smartcard redirection with Windows 2012 R2 * Fix issue with windows key functionality * Fix memory corruption when using rdp_out_unistr() * Fix workaround for the lack of support for alpha cursors * Fix silent exit when redirected when using CredSSP * Fix crash when starting rdesktop without domain specified while using CredSSP * Fix issue in SeamlessRDP protocol parser upon reconnect * Fix issue were a new SeamlessRDP application is respawned upon a reconnection -- Henrik Andersson 2014-10-31 rdesktop (1.8.2) * Support enhanced server redirection (Session broker 2012) * Support License Error Alert PDU * Changed default driver for printer redirection * Fix CredSSP login using non-ASCII username/password * Fix double login prompt bug with Win2008 server redirection * Fix keysym collisions * Fix mouse cursor with 2012 R2 * Fix local drive redirection with Win8 / Win2012 * Fix issue with mouse cursor hotspot * Fix issue with mouse / keyboard against VirtualBox RDP * Fix uncomplete czech keymap * Fix error in dutch keymap -- Henrik Andersson 2014-05-20 rdesktop (1.8.1) * Fix a typo in configure.ac * Fix a bug which made rdesktop steal CPU cycles. * Fix issue with reconnect, make use of deactivate variable * Added 4 new disconnect reasons with exit codes * Fix issues of window handling in SeamlessRDP parts of rdesktop * Fix a backward compability with OpenSSL < 0.9.9 * Fix a bug when code needs a x window available but there are none. * Fix a sigsegv zeroing memory * Fix a 64bit portability issue -- Henrik Andersson 2013-11-18 rdesktop (1.8.0) * Support for protocol negotiation eg. SSL/TLSv1 and CredSSP * Support for CredSSP + Kerberos authentication (NLA) * Support for smart card single-sign-on * Support passing smart card pin as password as argument * Added IPC for controlling a master rdesktop process * Support for connection sharing when using SeamlessRDP * Improved handling of network connection failures * Autoreconnect using the connection cookie at network failure * Fix a few smart card issues * Fix bug with mouse scroll handling * Fix for left/right braces in Italian keymap * Fix crash and memory leak in local drive redirection * Fixes issues with license files loading/saving -- Henrik Andersson 2013-08-09 rdesktop (1.7.1) * Fix clipboard issue when not building with unicode support * Fix compilation against newer PCSC lite versions * Fix for per-device license mode on Windows 2008 R2 terminal server * Fix building 64bit version with static openssl linkage * Rewrite of smartcard handling for 64bit support, fixes several bugs * Improved license handling using XDG directories -- Henrik Andersson 2012-01-09 rdesktop (1.7.0) * Security: Directory traversal vulnerability with disk redirection (disallow /.. requests) * New maintainer: Peter Åstrand * Brush cache support * Removed the hardcoded limit of the username length * Increased domain name length to 255 chars * Improved compatibility with PulseAudio/padsp * Cleaned up and documented the return values * Keyboard fix: avoid stuck keys in certain cases * Support for new pointers * License has been changed to GPLv3 * EWMH fixes for 64-bit machines * RandR support: automatically resize session if using relative screen size * Improved support for Windows 2008 Session Broker * Japanese keyboard map has been improved * New keyboard map: fr-bepo * Many stability fixes regarding smart card redirection * Windows 2008 R2 / 7: Fix sound playback when not using other redirections * Windows 2008 R2 / 7: Solve disk redirection read-only issues * Windows 2008 R2 / 7: Solve issue with recursive deletion * Avoid exit when printing, if lpr command terminates early -- Peter Åstrand 2011-04-13 rdesktop (1.6.0) * Fix for crash with recent versions of X.Org * Fix for potential vulnerability against compromised/malicious servers (reported by iDefense) * Fix for Windows 2008 Server * ALSA driver added * Sound drivers can now be selected at runtime * Smartcard support (Alexi Volkov ) * Send physical mouse buttons rather than logical ones -- Matthew Chapman Sat, 11 May 2008 16:12:20 +1100 (AEDT) rdesktop (1.5.0) * SeamlessRDP - seamless windows support * Keymap fixes * Fix connection issues with Windows XP RTM * Keyboard handling improvements and fixes * SGI/Irix sound-driver fixes * Support for clipboard INCR protocol * Session Directory support (patch from Brian Chapeau ) * Support for long filenames on redirected drives * XOR ellipse drawing fix * Clipboard unicode support (Ilya Konstantinov) * Fix display issues with exotic color depths (30bpp, 32bpp, etc) (Ilya Konstantinov) * Large file support * The default color depth is now the depth of the root window * Basic support for Windows Vista Beta 2 * Fix high cpu-usage in OSS-driver -- Peter Astrand Wed, 13 Sep 2006 15:11:39 +0200 (CEST) rdesktop (1.4.1) * persistent bitmap cache optimisations * support for more RDP-orders (ellipse, polygon) * libao sound-driver (for Mac OSX and others) * Unicode support for transmitted strings/filenames * Added korean keymap * Xembed fixes to work with krdc correctly * Portability fixes * Support for RDP-compression (all bpps) * process RDP recv queue if send queue is full (Debian bug #246461) * SGI/Irix sound-driver fixes -- Michael Gernoth Sun, 8 May 2005 19:55:35 +0200 (CEST) rdesktop (1.4.0) * Basic disk-, parallel-, printer- and serial-redirection * Fix timezone-redirection * Backing-store fixes * Fix client-IP sent to TS * XEmbed support for embedding rdesktop in other applications (KRDC) * Support for setting the RDP5 experience * Keyboard and keymap fixes * Performance improvements * Report disconnect-reason * Support for RDP-compression (currently only for 8bpp) * Support for persistent bitmap caching * Sound-driver for SGI/Irix -- Michael Gernoth Sun, 6 Mar 2005 22:09:55 +0100 (CET) rdesktop (1.3.1) * Crypto fixes for RDP5 * Keyboard and keymap fixes * some endianess fixes for high color * portability enhancements -- Matthew Chapman Tue, 21 Jan 2004 20:34 rdesktop (1.3.0) * RDP5 * 15, 16 and 24 bit color depths * Basic clipboard redirection * Sound * IPv6 * Attaching to console on Windows 2003 -- Peter Astrand Wed, 29 Oct 2003 16:40:58 +0100 (CET) rdesktop (1.2.0) * new - more portable - key mapping code * support for "high" (128-bit) encryption * toggling out of full-screen mode with Ctrl-Alt-Enter * a few extra options including host:port syntax * many, many bug fixes and optimisations -- Matthew Chapman Thu, 30 Jan 2003 04:29 rdesktop (1.1.0) * solves arith.c licensing issue by taking big number routines from OpenSSL * keyboard support not merged from unified patches yet * still no manpage -- Matthew Chapman Mon, 17 Sep 2001 23:14:28 +1000 (AEST) rdesktop (1.0.0) * initial release -- Matthew Chapman rdesktop-1.8.3/doc/keymapping.txt0000664000770100510440000001722511254437404015762 0ustar hean01hean01Keyboard mapping ================ This release of rdesktop uses a new, portable keyboard mapping implementation. It should hopefully work on all X11 systems. This new implementation only looks at X11 keysyms: Not on (nonportable) keycodes or modifier status. This means that rdesktop will obey your local keyboard configuration. For example, if you have swapped CapsLock and Control, rdesktop will use this mapping. XKB is currently not used. It seems like a good idea to me, but since some X servers (like Xvnc) does not support XKB, we still need to use the plain old interface as well, at least. There are still some small problems. * CapsLock: CapsLock changes are never sent to the RDP server. rdesktop does not know which keys that are modified by CapsLock and which are not. So, the CapsLock indicator in Wordpad etc will always be off. Composing/Multi_key is supported. For more information, see: MIT: $SRC/xc/nls/X11/locale/Compose/iso8859-1 XFree86: /usr/X11R6/lib/X11/locale/*/Compose Solaris' Openwin: /usr/openwin/include/X11/Suncompose.h /usr/openwin/lib/locale/*/Compose Irix6: compose(5) Keymap files ============ The names of the keymaps follows RFC1766. (You can find a translation from Windows keyboard layout numbers to keymap names by looking at HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MIME\Database\RFC1766 in the registry.) Contents of keymap files ======================== The keymaps are line based. There are four different types of lines: 1) include lines Syntax: include Example: include common 2) map lines Syntax: map Example: map 0x41d Map-lines specifies how the remote RDP server should interpret the sent scancodes. 3) Translation lines Syntax: [flags..] Example: onehalf 0x29 shift The scancode can be found in scancodes.h. Note: The scancode value for extended keys can be calculated by OR:ing with 0x80. Example: The Delete key have the scancode sequence 0xe0, 0x52. You can get the scancode value to put into the map file by running: python -c "print hex(0x80 | 0x52)" If flags are "altgr", "shift", the scancode sent for this keysym will be prefixed with AltGr, or Shift. If flags includes "addupper", a translation for this keysyms uppercase name will be added as well, in addition to the non-uppercase name. Example: x 2d addupper ...will add an translation for "X" automatically, just like if you would specify: X 2d shift If flags include "localstate", the modifier to send will be determined by the local modifier state. If flags is "inhibit", nothing will be sent to the server. If flags is "numlock", rdesktop will make sure that the remote NumLock state is on before generating the key event. Otherwise, it will make sure NumLock is off. 4) enable_compose If any line starts with the keyword "enable_compose", rdesktop will enable local Compose/Multi_key handling. Enabling this will often make it impossible to compose characters with dead keys (on the remote side). This is because when local compose support is enabled, dead keys will not be sent to the remote side. 5) sequence lines Syntax: sequence ... Examples: sequence eacute dead_acute e sequence F12 f o o at e x a m p l e period c o m Sequence lines allows you to specify that multiple scancodes should be sent to the RDP server, in response to one X11 keyboard event. Note: The sequence is sent at the X11 KeyPress event. Nothing is sent at KeyRelease. 6) keyboard_type lines Syntax: keyboard_type keyboard_type lines specifies the keyboard type. Default value is 0x4 (en-us 101/104 keys keyboard). 7) keyboard_subtype lines Syntax: keyboard_subtype keyboard_subtype lines specifies the keyboard subtype. Default value is 0x0 (en-us 101/104 keys keyboard). 8) keyboard_functionkeys lines Syntax: keyboard_functionkeys keyboard_functionkeys specifies the number of keyboard function keys. Default value is 0xc (12, for standard 101/104 keys keyboard). Suggested X11 keysym mapping on PCs =================================== Unfortunately, there is no standard for which keysyms a given key should generate. If you have a PC-keyboard with Windows keys, I suggest this mapping: Keyboard keys: CtrlLeft WinLeft AltLeft Space AltGr WinRight Menu CtrlRight ...should generate keysyms: Control_L Super_L Alt_L space Mode_switch Super_R Menu Control_R Additionally: Shift-Alt should produce Meta_L Shift-AltGr should produce Multi_Key. Use a modifier-map like this: shift Shift_L (0x32), Shift_R (0x3e) lock Caps_Lock (0x25) control Control_L (0x42), Control_R (0x6d) mod1 Alt_L (0x40) mod2 Num_Lock (0x4d) mod3 Mode_switch (0x71) mod4 Super_L (0x73), Super_R (0x74) mod5 Scroll_Lock (0x4e) Updating / writing keymap files =============================== When writing new or updating keymap files, please use comments and blanks, to increase readability. The "sv" keymap is a good template. When you need to add a translation to a keymap file, do: 1. Get the "key number" for this key, by looking at keynums.png. 2. Take a look at scancodes.h, and look for SCANCODE_KEY_. The scancode value is at the end of the line. If the line contains (SCANCODE_EXTENDED | 0xsomething), then you should OR 0x80 to this value. For example, you can do: python -c "print hex(0x80 | 0xsomething)" 3. Put the scancode (from step 2) and keysym name (found in the error message) into the keymap file. Special keys ============ * The combination Ctrl-Alt-Enter toggles between fullscreen and non-fullscreen mode. * Meta, Hyper and Super are treated as windows keys. RDP4 does not support the windows keys though, so if you are running RDP4, these keys will translate to Ctrl-Esc. Links ===== http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html Test cases ========== When changing the keyboard code, make sure all these tests in Notepad works: 1. Ctrl+f should bring up Find dialog, with CapsLock both on and off. 2. Ctrl+Shift+arrows should mark text, with CapsLock both on and off. 3. Test a sequence, like egrave. If you don't have this symbol in your keyboard layout, try something like: xmodmap -e "keycode 49 = egrave" 4. Test a char generated with AltGr, such as @ on a swedish keyboard. 5. Test Ctrl-Alt-Delete. 6. Ctrl-Alt-Enter should toggle fullscreen. 7. Test NumLock synchronization using the -N option. Excel is able to indicate the current NumLock state. Verify that the status is updated correctly on reconnects. 8. Test the Windows keys, standalone as well as in combination with, say, E. 9. Make sure the system menu (via Alt-space) cannot be accessed in single app mode. 10. Make sure keymaps can be loaded from ~/.rdesktop/keymaps, KEYMAP_PATH, $CWD/keymaps, and from an absolute path. 11. Press Shift, then press a key modified by shift, the release shift, then release the other key. Do this in a speedy fasion. Make sure the shift state is not stuck down. 12. Test all numpad keys, when not using the -N option. 13. Map a single, un-shifted key (such as F1) to XK_A: xmodmap -e "keycode 67 = A A" Perform in Notepad: * Write some text * Press F1 * Press b * Release b * Release F1 Verify that shift is not stuck down, by clicking on the text. 14. Use a keyboard layout where Meta_L can be generated with Shift_R + Alt_L. Then: * Start Notepad * Press Shift_R * Press Alt_L * Release Shift_R * Release Alt_L * Press "e" Verify that you get an "e" in Notepad, rather than start Windows Explorer. rdesktop-1.8.3/doc/keymap-names.txt0000664000770100510440000000617707742337340016216 0ustar hean01hean01 0x0436 af Afrikaans 0x041C sq Albanian 0x0001 ar Arabic 0x0401 ar-sa Arabic (Saudi Arabia) 0x0801 ar-iq Arabic (Iraq) 0x0C01 ar-eg Arabic (Egypt) 0x1001 ar-ly Arabic (Libya) 0x1401 ar-dz Arabic (Algeria) 0x1801 ar-ma Arabic (Morocco) 0x1C01 ar-tn Arabic (Tunisia) 0x2001 ar-om Arabic (Oman) 0x2401 ar-ye Arabic (Yemen) 0x2801 ar-sy Arabic (Syria) 0x2C01 ar-jo Arabic (Jordan) 0x3001 ar-lb Arabic (Lebanon) 0x3401 ar-kw Arabic (Kuwait) 0x3801 ar-ae Arabic (U.A.E.) 0x3C01 ar-bh Arabic (Bahrain) 0x4001 ar-qa Arabic (Qatar) 0x042D eu Basque 0x0402 bg Bulgarian 0x0423 be Belarusian 0x0403 ca Catalan 0x0004 zh Chinese 0x0404 zh-tw Chinese (Taiwan) 0x0804 zh-cn Chinese (China) 0x0C04 zh-hk Chinese (Hong Kong SAR) 0x1004 zh-sg Chinese (Singapore) 0x041A hr Croatian 0x0405 cs Czech 0x0406 da Danish 0x0413 nl Dutch (Netherlands) 0x0813 nl-be Dutch (Belgium) 0x0009 en English 0x0409 en-us English (United States) 0x0809 en-gb English (United Kingdom) 0x0C09 en-au English (Australia) 0x1009 en-ca English (Canada) 0x1409 en-nz English (New Zealand) 0x1809 en-ie English (Ireland) 0x1C09 en-za English (South Africa) 0x2009 en-jm English (Jamaica) 0x2809 en-bz English (Belize) 0x2C09 en-tt English (Trinidad) 0x0425 et Estonian 0x0438 fo Faeroese 0x0429 fa Farsi 0x040B fi Finnish 0x040C fr French (France) 0x080C fr-be French (Belgium) 0x0C0C fr-ca French (Canada) 0x100C fr-ch French (Switzerland) 0x140C fr-lu French (Luxembourg) 0x043C gd Gaelic 0x0407 de German (Germany) 0x0807 de-ch German (Switzerland) 0x0C07 de-at German (Austria) 0x1007 de-lu German (Luxembourg) 0x1407 de-li German (Liechtenstein) 0x0408 el Greek 0x040D he Hebrew 0x0439 hi Hindi 0x040E hu Hungarian 0x040F is Icelandic 0x0421 in Indonesian 0x0410 it Italian (Italy) 0x0810 it-ch Italian (Switzerland) 0x0411 ja Japanese 0x0412 ko Korean 0x0426 lv Latvian 0x0427 lt Lithuanian 0x042F mk FYRO Macedonian 0x043E ms Malay (Malaysia) 0x043A mt Maltese 0x0414 no Norwegian (Bokmal) 0x0814 no Norwegian (Nynorsk) 0x0415 pl Polish 0x0416 pt-br Portuguese (Brazil) 0x0816 pt Portuguese (Portugal) 0x0417 rm Rhaeto-Romanic 0x0418 ro Romanian 0x0818 ro-mo Romanian (Moldova) 0x0419 ru Russian 0x0819 ru-mo Russian (Moldova) 0x0C1A sr Serbian (Cyrillic) 0x081A sr Serbian (Latin) 0x041B sk Slovak 0x0424 sl Slovenian 0x042E sb Sorbian 0x040A es Spanish (Traditional Sort) 0x080A es-mx Spanish (Mexico) 0x0C0A es Spanish (International Sort) 0x100A es-gt Spanish (Guatemala) 0x140A es-cr Spanish (Costa Rica) 0x180A es-pa Spanish (Panama) 0x1C0A es-do Spanish (Dominican Republic) 0x200A es-ve Spanish (Venezuela) 0x240A es-co Spanish (Colombia) 0x280A es-pe Spanish (Peru) 0x2C0A es-ar Spanish (Argentina) 0x300A es-ec Spanish (Ecuador) 0x340A es-cl Spanish (Chile) 0x380A es-uy Spanish (Uruguay) 0x3C0A es-py Spanish (Paraguay) 0x400A es-bo Spanish (Bolivia) 0x440A es-sv Spanish (El Salvador) 0x480A es-hn Spanish (Honduras) 0x4C0A es-ni Spanish (Nicaragua) 0x500A es-pr Spanish (Puerto Rico) 0x0430 sx Sutu 0x041D sv Swedish 0x081D sv-fi Swedish (Finland) 0x041E th Thai 0x0431 ts Tsonga 0x0432 tn Tswana 0x041F tr Turkish 0x0422 uk Ukrainian 0x0420 ur Urdu 0x042A vi Vietnamese 0x0434 xh Xhosa 0x043D ji Yiddish 0x0435 zu Zulu rdesktop-1.8.3/doc/ipv6.txt0000664000770100510440000000201510013523456014464 0ustar hean01hean01 IPv6 support in rdesktop ======================== The IPv6 support was developed by Mike Dawson : Attached is a patch to tcp.c to enable IPv6 support. Build with 'IPv6' defined to enable it. It's so far only been tested on Linux 2.4.21 connecting to Windows XP SP1. Since terminal services doesn't seem to bind to the ipv6 interface on XP I had to run 'netsh interface portproxy add v6tov4 listenport=3389 connectport=3389' from the windows command prompt to get it to work. rdesktop now supports numeric IPv6 addresses: It checks for two or more colons in an address to decide what it's dealing with so you can now do: rdesktop 2001:1:2:3::4 without it getting confused with an ipv4:port specification. I've also followed the square bracket convention used by browsers (http://www.ietf.org/rfc/rfc2732.txt) so if you want to specify a non-standard port with an ipv6 address you can use the format: rdesktop [2001:1:2:3::4]:3390 rdesktop-1.8.3/doc/licensing.txt0000664000770100510440000000557410562617006015574 0ustar hean01hean01 To be able to connect to Microsoft Windows 2000 Terminal Services (and probably later versions), you'll need to deal with licensing. This is complicated. This file is supposed to contain some information about how rdesktop works with Microsofts license systems. There's a lot of information on the MS web site, for example, http://support.microsoft.com/default.aspx?scid=kb;EN-US;287687. From the rdesktop mailing list: Peter Åstrand , 2003-02-06 > We are running rdesktop 1.2 on machine A and connects to a Windows 2000 > Server (machine B). The W2K machine has 5 real licenses installed ("Windows > 2000 Terminal Services Client Access License", "Open" type). This can be > verifier by using "Terminal Services Licensing". The problem is that all > issued licenses have an expire-date. The expire date for the license issued > to A was reached today, and no more connections could be made until we > changed the client name (by using -n). > > We also have another similiar systems, with Linux machine C and W2K server > D. This server has 200 licenses installed of the type "Select". On this > server, the issued licenses seems to be permanent: The expire date is set > to "-", and we have no problem with this system. > > The question of course is why the first system issues license with > expiration date, while the second system issues permanent licenses. Darryn Capes-Davis, 2003-02-07 > I have been through the problems and can tell you what is going > on. The main difference of Machine B (Server 1) and Machine D (Server > 2) is that from what I see Machine B has Service Pack 3 installed and > Machine D does not. You see in Service Pack 3 there was a change made > to TS Licencing in that Microsoft introduced a licence recovery > mechanism. To cut to the point (I don't know the details) rdesktop 1.2 > with SAVE_LICENCE defined works fine. In the new lic method the > terminal server expects a valid licence to be presented to renew > it. Otherwise it just expires it - and a day later you will see it > actually gone (it does housekeeping once a day)! So if SAVE_LICENCE > code is not enabled then it just expires and you can't use the licence > until it cleans it away - and this is where a little gotcha is - if > you move from using an rdesktop without SAVE_LICENCE to one with > SAVE_LICENCE then it still won't recover an 'expired' licence. You > have to wait for the daily housekeeping to clean it up - this really > had me going for half a day or so! This is exactly what happened to > you. > > The Server pre Spk 3 has the old model where licences never expire. To > recover a licence that you never wanted to use again you have to call > the Microsoft Clearing House. That's why they introduced the new > method. And if you upgrade a Pre Spk3 server to Spk3 then the licences > granted still stay with the old method - only new licences granted > will use the new expiry method. rdesktop-1.8.3/doc/patches.txt0000664000770100510440000002207007542070552015241 0ustar hean01hean01This file documents some of all patches for rdesktop, floating around the net, and how they are related to the current (CVS) version of rdesktop. Things left to do are marked with TBD (To Be Done). URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/Makefile.diff Description: Makefile changes which makes it possible to compile rdesktop on SunOS and OSF1. Status: Applied (slightly modified) URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/assar_19-7-2.hostlen.patch Description: Fix for hostnames longer than 30 chars. Status: Applied (revision 1.11 of secure.c) URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/backingstore+privatecolormap-for-19-3-9.patch Description: This adds support for 1) Private color maps (useful for 8 bpp mode) and 2) backingstore selection. Status: 1) is not needed anymore; rdesktop automatically uses Private color map in 8 bpp mode. 2) is, as far as I understand, also not need. rdesktop automatically uses a software backing store if the Xserver does not provide one. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/ben_xwin.c.diff Description: Fixes for CapsLock and NumLock. Status: Not needed anymore, with the new keyboard mapping implementation. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/ctrl1nohang.diff Description: Fixes problem with ctrl1 hangs. Status: Not needed anymore, with the new keyboard mapping implementation. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/downkeypatch.diff Description: Seems to keep track of the remote modifier status. Status: Not needed anymore, with the new keyboard mapping implementation. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/fasttext2+nobackpixmap.patch Description: (From http://mail.rdesktop.org/archive/2001/msg00218.html): 1) Added --no-backpixmap option to disable the ugly double drawing in xwin.c (I have a very robust backing storage in my X, so I don't need it ;) 2) More optimizations to text draw (previous fast-text patch was included in 192-3-6-2). In text drawing with solid background the glyphs are drawn with stippled fill instead of XCopyPlane (runs faster on my S3Trio64 with XFree 3.3.6, please test it on other configurations to validate this). The WinTach not show any improvement with this change, it seems to use all transparent background text draws, but with a old PC Magazine Winbench (3.1) doing the scroll text test the speed gain is significative. 3) My Previous patch to disable backing storage in fullscreen Status: 1) is not relevant any more, since rdesktop only uses backing store if the Xserver does not provide backing store. Need to examine if 2) and 3) are still useful. TBD. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/francisco_fix_patblt.html Description: The colors in patterns drawn with "pattern blt" order was inverted (fg & bg). (See the background of the yellow help banners) Status: Applied (in revision 1.29, 2002/07/14) URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/frank_1linerfix.html Description: ui_create_glyph was not called with ipattern. Status: Applied (in revision 1.29, 2002/07/14). URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/frank_fasttext.patch.txt Description: Some kind of performence improvements. Status: From what I can tell, this patch is no longer necessary. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/hostname-patch Description: (From http://mail.rdesktop.org/archive/2001/msg00163.html): rdesktop uses gethostname to figure out the hostname, but gethostname under linux returns an error when the hostname is longer than the buffer. This hack gives gethostname a 64 char buffer and then strips the first 16 chars or upto the first '.' and puts the result in hostname[16]. Status: Applied in version 1.10 of rdesktop.c. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/hove-19-7-2endian.diff Description: Includes a program for testing endianness. Status: rdesktop determines endianness at runtime. This patch is not needed anymore. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/mmihalik_19-7-3-keyfix-4.patch Description: Some kind of new alternative keyboard mapping imlementation. Status: Not needed anymore, with the new keyboard mapping implementation. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/norbert_fullscreen.patch Description: Fullscreen mode. Status: Applied. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/norbert_percent.txt Description: Makes is possible to specify RDP geometry based a percent value of the current desktop size. Status: Not applied. I don't think many people will need this. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/norbert_rdp_tcp_port.diff Description: Command line tcp port argument. Status: Applied. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/patch19-7-2.xyPos.emptyPassword.patch Description: This patch adds: 1) Support for empty passwords 2) Support for asking for password interactively 3) Support for ++ geometry. Status: 1) and 2) can be solved by the -P parameter; patch not needed. Functionality for 3) is currently missing. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdesktop-1.0.0-19-7-1-mmihalik-3.diff Description: Defines DO_GLYPH() etc. Status: As far as I understand, this patch is applied. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdesktop-1.0.0-mmihalik-1.diff Description: Misc drawing changes. Status: As far as I understand, this patch is applied. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdesktop-1.0.0-pl19-7-2-mmihalik-1.diff Description: Some kind of new alternative keyboard mapping implementation. Status: Not needed anymore, with the new keyboard mapping implementation. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdesktop-gmp.patch Description: Use GMP for RSA crypto. Status: Not needed since rdesktop now use OpenSSL for all of the crypto. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdesktop-new_kb.patch Description: Modifies one of the old keyboard mapping implementations in some way. Status: Not needed anymore, with the new keyboard mapping implementation. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdesktop-openssl.patch Description: Support for linking rdesktop with OpenSSL. Status: Not needed anymore, rdesktop can optionally use system OpenSSL. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdesktop.vncviewer_patch Description: Hack for making the old (broken) keyboard mapping implementation work with the VNC Xserver. Status: Not needed anymore, with the new keyboard mapping implementation. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdesktop_keymap.patch Description: Some kind of new alternative keyboard mapping implementation. Status: Not needed anymore, with the new keyboard mapping implementation. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/rdp-srvr-19-6-6.diff Description: Basic RDP server. Status: Not applied. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/scroll-to-death-patch.txt Description: Fixes scroll-to-death problem in Excel and other applications. Status: Not needed; fixed in another way in recent versions of rdesktop. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/spark-manpage-patch-19.4 Description: Adds a manual page. Status: Not needed; rdesktop contains a manual page now. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/spark-manpage-patch-19.4-1 Description: Adds a manual page. Status: Not needed; rdesktop contains a manual page now. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/spark_xinerama-patch2 Description: Adds XINERAMA support to rdesktop. Status: Not applied yet. TBD. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/svenni_dis_wmkeybnds.patch Description: Commandline flag to disable keyboard grabbing. Status: Applied. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/svenni_disable_bs_in_x-tiny-patch Description: Disables backing store for TinyX. Status: As far as I understand, this patch is not need any longer. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/vincent_19-7-2.license.patch Description: TBD Status: Not yet examined. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/vincent_19-7-2.secure.patch Description: Fixes a problem during the connection to a French NT4 TSE (a French NT4 TSE doesn't use encryptation). Status: Applied. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/vincent_19-7-3_excel.patch Description: Makes matrixes appear better, such as those found in Excel/toad etc. Status: Applied. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/vincent_8bpp.patch Description: Support a 8bpp display (256 colours). Status: An enhanced version is included in rdesktop; this patch is not needed any more. URL: http://bibl4.oru.se/projects/rdesktop/patch19/patches/vpypatch.txt Description: Various changes for one of the old keyboard stuff. Status: Not needed anymore, with the new keyboard mapping implementation. rdesktop-1.8.3/doc/redirection.txt0000664000770100510440000000272610105700461016113 0ustar hean01hean01 Syntax for configuring RDP redirection modules ============================================== General ------- All redirection is configured using the -r option. The general syntax is: -r : is the name of the redirection module. The following names are valid: disk, printer, lptport, comport, clipboard, sound. is interpreted by each redirection module. The redirection modules are described below. disk mapping ------------- Multiple mappings possible: yes Default: no disk redirected Syntax: -r disk:= Example: -r disk:home=/home/johndoe printer mapping --------------- Multiple mappings possible: yes Default: no printers redirected Syntax: -r printer: Example: -r printer:mydeskjet LPT port mapping ---------------- Multiple mappings possible: yes Default: no LPT ports redirected Syntax: -r lptport:= Example: -r lptport:LPT1=/dev/lp0 COM port mapping ---------------- Multiple mappings possible: yes Default: no COM ports redirected Syntax: -r comport:= Example: -r comport:COM1=/dev/ttyS0 clipboard mapping ----------------- Multiple mappings possible: no Default: yes Syntax: -r clipboard:[yes|no] Example: -r clipboard:no sound mapping ------------- Multiple mappings possible: no Default: off Syntax: -r sound:[local|off|remote] "local" means "Bring to this computer" "off" means "Do not play" "remote" means "Leave at remote computer" Example: -r sound:remote rdesktop-1.8.3/doc/rdesktop.10000664000770100510440000003006512216533757014776 0ustar hean01hean01.TH rdesktop 1 "November 2005" .SH NAME .I rdesktop \- Remote Desktop Protocol client .SH SYNOPSIS .B rdesktop [options] server[:port] .br .SH DESCRIPTION .I rdesktop is a client for Remote Desktop Protocol (RDP), used in a number of Microsoft products including Windows NT Terminal Server, Windows 2000 Server, Windows XP and Windows 2003 Server. .SH OPTIONS .TP .BR "-u " Username for authentication on the server. .TP .BR "-d " Domain for authentication. .TP .BR "-s " Startup shell for the user - starts a specific application instead of Explore. If SeamlessRDP is enabled this is the application which i started in seamless mode. .TP .BR "-c " The initial working directory for the user. Often used in combination with -s to set up a fixed login environment. .TP .BR "-p " The password to authenticate with. Note that this may have no effect if "Always prompt for password" is enabled on the server. WARNING: if you specify a password on the command line it may be visible to other users when they use tools like ps. Use -p - to make rdesktop request a password at startup (from standard input). .TP .BR "-n " Client hostname. Normally rdesktop automatically obtains the hostname of the client. .TP .BR "-k " Keyboard layout to emulate. This requires a corresponding keymap file to be installed. The standard keymaps provided with rdesktop follow the RFC1766 naming scheme: a language code followed by a country code if necessary - e.g. en-us, en-gb, de, fr, sv, etc. The default keyboard map depends on the current locale (LC_* and LANG environment variables). If the current locale is unknown, the default keyboard map is en-us (a US English keyboard). The keyboard maps are file names, which means that they are case sensitive. The standard keymaps are all in lowercase. The keyboard maps are searched relative to the directories $HOME/.rdesktop/keymaps, KEYMAP_PATH (specified at build time), and $CWD/keymaps, in this order. The keyboard-map argument can also be an absolute filename. The special value `none' can be used instead of a keyboard map. In this case, rdesktop will guess the scancodes from the X11 event key codes using an internal mapping method. This method only supports the basic alphanumeric keys and may not work properly on all platforms so its use is discouraged. .TP .BR "-g " Desktop geometry (WxH). If geometry is the special word "workarea", the geometry will be fetched from the extended window manager hints property _NET_WORKAREA, from the root window. The geometry can also be specified as a percentage of the whole screen, e.g. "-g 80%". If the specified geometry depends on the screen size, and the screen size is changed, rdesktop will automatically reconnect using the new screen size. This requires that rdesktop has been compiled with RandR support. .TP .BR "-i" Use password as smartcard pin. If a valid user certificate is matched in smart card reader the password passed with \f-p\fR argument is used as pin for the smart card. This feature also requires that smart card redirection is used using \f-r scard\fR argument. .TP .BR "-f" Enable fullscreen mode. This overrides the window manager and causes the rdesktop window to fully cover the current screen. Fullscreen mode can be toggled at any time using Ctrl-Alt-Enter. .TP .BR "-b" Force the server to send screen updates as bitmaps rather than using higher-level drawing operations. .TP .BR "-t" Disable use of remote control. This will disable features like seamless connection sharing. .TP .BR "-A " Enable SeamlessRDP by specifying the path to seamless rdp shell. In this mode, rdesktop creates a X11 window for each window on the server side. This mode requires the SeamlessRDP server side component, which is available from \fIhttp://www.cendio.com/seamlessrdp/\fR. When using this option, you should normally specify a startup shell which launches the desired application through SeamlessRDP. Example: rdesktop -A 'c:\\seamlessrdp\\seamlessrdpshell.exe' -s 'notepad' mywts.domain.com Any subsequential call to the above commandline example will make use of the seamless connection sharing feature which spawns another notepad in the current connection to the specified server and then exit. .TP .BR "-B" Use the BackingStore of the Xserver instead of the integrated one in rdesktop. .TP .BR "-e" Disable encryption. This option is only needed (and will only work) if you have a French version of NT TSE. .TP .BR "-E" Disable encryption from client to server. This sends an encrypted login packet, but everything after this is unencrypted (including interactive logins). .TP .BR "-m" Do not send mouse motion events. This saves bandwidth, although some Windows applications may rely on receiving mouse motion. .TP .BR "-C" Use private colourmap. This will improve colour accuracy on an 8-bit display, but rdesktop will appear in false colour when not focused. .TP .BR "-D" Hide window manager decorations, by using MWM hints. .TP .BR "-K" Do not override window manager key bindings. By default rdesktop attempts to grab all keyboard input when it is in focus. .TP .BR "-S