From 1123323fda6d128fb98b0427e0ea5f6a2dc9e632 Mon Sep 17 00:00:00 2001 From: Laxmikant Rashinkar Date: Wed, 19 Sep 2012 20:51:34 -0700 Subject: [PATCH] o moved from GNU General Public License to Apache License, Version 2.0 o applied new coding standards to all .c files o moved some files around --- COPYING | 482 +--- Coding_Style.odt | Bin 0 -> 23360 bytes astyle_config.as | 59 + common/arch.h | 39 +- common/d3des.c | 732 ++--- common/defines.h | 40 +- common/file.c | 564 ++-- common/file.h | 42 +- common/file_loc.h | 40 +- common/list.c | 289 +- common/list.h | 42 +- common/log.c | 909 ++++--- common/log.h | 39 +- common/os_calls.c | 2932 ++++++++++---------- common/os_calls.h | 42 +- common/parse.h | 50 +- common/ssl_calls.c | 463 ++-- common/ssl_calls.h | 36 +- common/thread_calls.c | 175 +- common/thread_calls.h | 43 +- common/trans.c | 727 ++--- common/trans.h | 43 +- common/xrdp_client_info.h | 43 +- fontdump/fontdump.c | 796 +++--- freerdp/xrdp-color.c | 539 ++-- freerdp/xrdp-color.h | 36 +- freerdp/xrdp-freerdp.c | 1315 ++++----- freerdp/xrdp-freerdp.h | 40 +- freerdp1/xrdp-color.c | 499 ++-- freerdp1/xrdp-freerdp.c | 2980 +++++++++++---------- genkeymap/genkeymap.c | 150 +- keygen/keygen.c | 742 +++--- libxrdp/libxrdp.c | 1295 ++++----- libxrdp/libxrdp.h | 40 +- libxrdp/libxrdpinc.h | 40 +- libxrdp/xrdp_bitmap_compress.c | 2616 +++++++++--------- libxrdp/xrdp_channel.c | 246 +- libxrdp/xrdp_fastpath.c | 281 +- libxrdp/xrdp_iso.c | 307 ++- libxrdp/xrdp_jpeg_compress.c | 313 +-- libxrdp/xrdp_mcs.c | 1301 ++++----- libxrdp/xrdp_orders.c | 3851 ++++++++++++++------------- libxrdp/xrdp_orders_rail.c | 1046 ++++---- libxrdp/xrdp_rdp.c | 2595 +++++++++--------- libxrdp/xrdp_sec.c | 1799 +++++++------ libxrdp/xrdp_surface.c | 193 +- libxrdp/xrdp_tcp.c | 114 +- mc/mc.c | 125 +- mc/mc.h | 40 +- rdp/rdp.c | 569 ++-- rdp/rdp.h | 42 +- rdp/rdp_bitmap.c | 1735 ++++++------ rdp/rdp_iso.c | 348 +-- rdp/rdp_lic.c | 559 ++-- rdp/rdp_mcs.c | 1120 ++++---- rdp/rdp_orders.c | 2748 ++++++++++--------- rdp/rdp_rdp.c | 1730 ++++++------ rdp/rdp_sec.c | 1066 ++++---- rdp/rdp_tcp.c | 282 +- readme.txt | 2 +- sesman/access.c | 205 +- sesman/access.h | 35 +- sesman/auth.h | 35 +- sesman/chansrv/chansrv.c | 1722 ++++++------ sesman/chansrv/clipboard.c | 2107 ++++++++------- sesman/chansrv/devredir.c | 14 +- sesman/chansrv/rail.c | 854 +++--- sesman/chansrv/sound.c | 768 +++--- sesman/chansrv/xcommon.c | 206 +- sesman/config.c | 580 ++-- sesman/config.h | 36 +- sesman/env.c | 193 +- sesman/env.h | 40 +- sesman/libscp/libscp.h | 35 +- sesman/libscp/libscp_commands.h | 35 +- sesman/libscp/libscp_commands_mng.h | 35 +- sesman/libscp/libscp_connection.c | 71 +- sesman/libscp/libscp_connection.h | 42 +- sesman/libscp/libscp_init.c | 56 +- sesman/libscp/libscp_init.h | 40 +- sesman/libscp/libscp_lock.c | 188 +- sesman/libscp/libscp_lock.h | 36 +- sesman/libscp/libscp_session.c | 691 ++--- sesman/libscp/libscp_session.h | 35 +- sesman/libscp/libscp_tcp.c | 182 +- sesman/libscp/libscp_tcp.h | 35 +- sesman/libscp/libscp_types.h | 37 +- sesman/libscp/libscp_types_mng.h | 35 +- sesman/libscp/libscp_v0.c | 666 ++--- sesman/libscp/libscp_v0.h | 46 +- sesman/libscp/libscp_v1c.c | 783 +++--- sesman/libscp/libscp_v1c.h | 35 +- sesman/libscp/libscp_v1c_mng.c | 515 ++-- sesman/libscp/libscp_v1c_mng.h | 35 +- sesman/libscp/libscp_v1s.c | 1171 ++++---- sesman/libscp/libscp_v1s.h | 35 +- sesman/libscp/libscp_v1s_mng.c | 539 ++-- sesman/libscp/libscp_v1s_mng.h | 35 +- sesman/libscp/libscp_vX.c | 69 +- sesman/libscp/libscp_vX.h | 37 +- sesman/lock.c | 108 +- sesman/lock.h | 35 +- sesman/scp.c | 158 +- sesman/scp.h | 35 +- sesman/scp_v0.c | 234 +- sesman/scp_v0.h | 39 +- sesman/scp_v1.c | 383 +-- sesman/scp_v1.h | 39 +- sesman/scp_v1_mng.c | 226 +- sesman/scp_v1_mng.h | 35 +- sesman/sesman.c | 594 +++-- sesman/sesman.h | 35 +- sesman/session.c | 1571 +++++------ sesman/session.h | 35 +- sesman/sessvc/sessvc.c | 229 +- sesman/sig.c | 291 +- sesman/sig.h | 36 +- sesman/thread.c | 227 +- sesman/thread.h | 35 +- sesman/tools/dis.c | 111 +- sesman/tools/sesadmin.c | 250 +- sesman/tools/sesrun.c | 204 +- sesman/tools/sestest.c | 362 +-- sesman/tools/tcp.c | 207 +- sesman/tools/tcp.h | 35 +- sesman/tools/xcon.c | 67 +- sesman/verify_user.c | 457 ++-- sesman/verify_user_kerberos.c | 630 +++-- sesman/verify_user_pam.c | 354 +-- sesman/verify_user_pam_userpass.c | 122 +- tests/nx/client.sh | 13 - tests/nx/server.sh | 12 - tests/tcp_proxy/Makefile | 12 + tests/tcp_proxy/arch.h | 80 - tests/tcp_proxy/main.c | 73 +- tests/tcp_proxy/os_calls.c | 1449 ---------- tests/tcp_proxy/os_calls.h | 208 -- tests/xdemo/README.txt | 3 - tests/xdemo/bmp_parser.c | 204 -- tests/xdemo/commit.txt | 1 - tests/xdemo/common.h | 19 - tests/xdemo/xdemo.c | 674 ----- tests/xdemo/yosemite.bmp | Bin 1843254 -> 0 bytes vnc/vnc.c | 2309 ++++++++-------- vnc/vnc.h | 40 +- xorg/X11R7.6/buildx.sh | 13 +- xorg/X11R7.6/rdp/rdpCopyArea.c | 875 +++--- xorg/X11R7.6/rdp/rdpCopyPlane.c | 300 ++- xorg/X11R7.6/rdp/rdpFillPolygon.c | 326 +-- xorg/X11R7.6/rdp/rdpFillSpans.c | 113 +- xorg/X11R7.6/rdp/rdpImageGlyphBlt.c | 266 +- xorg/X11R7.6/rdp/rdpImageText16.c | 268 +- xorg/X11R7.6/rdp/rdpImageText8.c | 268 +- xorg/X11R7.6/rdp/rdpPolyArc.c | 322 +-- xorg/X11R7.6/rdp/rdpPolyFillArc.c | 322 +-- xorg/X11R7.6/rdp/rdpPolyFillRect.c | 392 +-- xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c | 268 +- xorg/X11R7.6/rdp/rdpPolyPoint.c | 417 +-- xorg/X11R7.6/rdp/rdpPolyRectangle.c | 449 ++-- xorg/X11R7.6/rdp/rdpPolySegment.c | 309 ++- xorg/X11R7.6/rdp/rdpPolyText16.c | 272 +- xorg/X11R7.6/rdp/rdpPolyText8.c | 272 +- xorg/X11R7.6/rdp/rdpPolylines.c | 379 +-- xorg/X11R7.6/rdp/rdpPushPixels.c | 260 +- xorg/X11R7.6/rdp/rdpPutImage.c | 245 +- xorg/X11R7.6/rdp/rdpSetSpans.c | 175 +- xorg/X11R7.6/rdp/rdpdraw.c | 1778 +++++++------ xorg/X11R7.6/rdp/rdpinput.c | 1377 +++++----- xorg/X11R7.6/rdp/rdpmain.c | 882 +++--- xorg/X11R7.6/rdp/rdpmisc.c | 523 ++-- xorg/X11R7.6/rdp/rdprandr.c | 289 +- xorg/X11R7.6/rdp/rdpup.c | 2648 +++++++++--------- xorg/tests/{ => nx}/client.sh | 0 xorg/tests/{ => nx}/server.sh | 0 xorg/tests/tcp_proxy/Makefile | 15 - xorg/tests/tcp_proxy/main.c | 265 -- xorg/tests/xdemo/README.txt | 2 +- xorg/tests/xdemo/bmp_parser.c | 60 +- xorg/tests/xdemo/common.h | 18 + xorg/tests/xdemo/xdemo.c | 519 ++-- xrdp/funcs.c | 391 +-- xrdp/lang.c | 406 +-- xrdp/xrdp.c | 865 +++--- xrdp/xrdp.h | 40 +- xrdp/xrdp_bitmap.c | 3220 +++++++++++----------- xrdp/xrdp_cache.c | 996 +++---- xrdp/xrdp_font.c | 359 +-- xrdp/xrdp_listen.c | 747 +++--- xrdp/xrdp_login_wnd.c | 1021 +++---- xrdp/xrdp_mm.c | 3596 +++++++++++++------------ xrdp/xrdp_painter.c | 1470 +++++----- xrdp/xrdp_process.c | 310 ++- xrdp/xrdp_region.c | 535 ++-- xrdp/xrdp_types.h | 39 +- xrdp/xrdp_wm.c | 2971 +++++++++++---------- xrdp/xrdpwin.c | 1033 +++---- xrdpapi/simple.c | 169 +- xrdpapi/xrdpapi.c | 558 ++-- xrdpapi/xrdpapi.h | 7 +- xup/xup.c | 1477 +++++----- xup/xup.h | 40 +- 201 files changed, 51410 insertions(+), 49613 deletions(-) create mode 100644 Coding_Style.odt create mode 100644 astyle_config.as delete mode 100755 tests/nx/client.sh delete mode 100755 tests/nx/server.sh create mode 100644 tests/tcp_proxy/Makefile delete mode 100644 tests/tcp_proxy/arch.h delete mode 100644 tests/tcp_proxy/os_calls.c delete mode 100644 tests/tcp_proxy/os_calls.h delete mode 100644 tests/xdemo/README.txt delete mode 100644 tests/xdemo/bmp_parser.c delete mode 100644 tests/xdemo/commit.txt delete mode 100644 tests/xdemo/common.h delete mode 100644 tests/xdemo/xdemo.c delete mode 100644 tests/xdemo/yosemite.bmp rename xorg/tests/{ => nx}/client.sh (100%) rename xorg/tests/{ => nx}/server.sh (100%) delete mode 100644 xorg/tests/tcp_proxy/Makefile delete mode 100644 xorg/tests/tcp_proxy/main.c diff --git a/COPYING b/COPYING index 10b86d59..08dea940 100644 --- a/COPYING +++ b/COPYING @@ -1,372 +1,176 @@ +Apache License, Version 2.0 -special clause for libxrdp and librdp, both based on rdesktop -these libraries link to openssl +Version 2.0, January 2004 - This software is released under the GNU General Public License - (reproduced below) with the additional exemption that compiling, - linking, and/or using OpenSSL together with this software is - allowed. +http://www.apache.org/licenses/ ---- +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -special clause for xrdp, that main executable -for linking with proprietary modules +1. Definitions. - Linking this library statically or dynamically with other modules - is making a combined work based on this library. Thus, the terms - and conditions of the GNU General Public License cover the whole - combination. +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. - As a special exception, the copyright holders of this library - give you permission to link this library with independent modules - to produce an executable, regardless of the license terms of - these independent modules, and to copy and distribute the resulting - executable under terms of your choice, provided that you also meet, - for each linked independent module, the terms and conditions of the - license of that module. An independent module is a module which is - not derived from or based on this library. If you modify this - library, you may extend this exception to your version of the - library, but you are not obliged to do so. If you do not wish - to do so, delete this exception statement from your version. +"Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License. ---- +"Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control +with that entity. For the purposes of this definition, "control" means +(i) the power, direct or indirect, to cause the direction or management +of such entity, whether by contract or otherwise, or (ii) ownership of +fifty percent (50%) or more of the outstanding shares, or +(iii) beneficial ownership of such entity. - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. - Preamble +"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled +object code, generated documentation, and conversions to other media types. - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that is +included in or attached to the work (an example is provided in the Appendix below). - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, as a +whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, or +merely link (or bind by name) to the interfaces of, the Work and +Derivative Works thereof. - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or Derivative +Works thereof, that is intentionally submitted to Licensor for inclusion in the +Work by the copyright owner or by an individual or Legal Entity authorized to +submit on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently incorporated +within the Work. - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. +2. Grant of Copyright License. Subject to the terms and conditions of this License, +each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute +the Work and such Derivative Works in Source or Object form. - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. +3. Grant of Patent License. Subject to the terms and conditions of this License, +each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise transfer +the Work, where such license applies only to those patent claims licensable by such +Contributor that are necessarily infringed by their Contribution(s) alone or by +combination of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution +incorporated within the Work constitutes direct or contributory patent infringement, +then any patent licenses granted to You under this License for that Work shall +terminate as of the date such litigation is filed. - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative +Works thereof in any medium, with or without modifications, and in Source or Object +form, provided that You meet the following conditions: - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +You must give any other recipients of the Work or Derivative Works a copy of this +License; and - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". +You must cause any modified files to carry prominent notices stating that You changed +the files; and -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of the Derivative Works; and - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the attribution +notices contained within such NOTICE file, excluding those notices that do not pertain +to any part of the Derivative Works, in at least one of the following places: within a +NOTICE text file distributed as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, within a display +generated by the Derivative Works, if and wherever such third-party notices normally +appear. The contents of the NOTICE file are for informational purposes only and do not +modify the License. You may add Your own attribution notices within Derivative Works +that You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as modifying +the License. You may add Your own copyright statement to Your modifications and may +provide additional or different license terms and conditions for use, reproduction, +or distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution +intentionally submitted for inclusion in the Work by You to the Licensor shall be under +the terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any +separate license agreement you may have executed with Licensor regarding such Contributions. - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: +6. Trademarks. This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for reasonable and +customary use in describing the origin of the Work and reproducing the content of +the NOTICE file. - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, +Licensor provides the Work (and each Contributor provides its Contributions) on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for +determining the appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. +8. Limitation of Liability. In no event and under no legal theory, whether in tort +(including negligence), contract, or otherwise, unless required by applicable law +(such as deliberate and grossly negligent acts) or agreed to in writing, shall any +Contributor be liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a result of this +License or out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or any +and all other commercial damages or losses), even if such Contributor has been advised +of the possibility of such damages. - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. +9. Accepting Warranty or Additional Liability. While redistributing the Work or +Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance +of support, warranty, indemnity, or other liability obligations and/or rights consistent +with this License. However, in accepting such obligations, You may act only on Your +own behalf and on Your sole responsibility, not on behalf of any other Contributor, +and only if You agree to indemnify, defend, and hold each Contributor harmless for any +liability incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. +END OF TERMS AND CONDITIONS -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. +APPENDIX: How to apply the Apache License to your work +To apply the Apache License to your work, attach the following boilerplate notice, +with the fields enclosed by brackets "[]" replaced with your own identifying +information. (Don't include the brackets!) The text should be enclosed in the +appropriate comment syntax for the file format. We also recommend that a file or class +name and description of purpose be included on the same "printed page" as the +copyright notice for easier identification within third-party archives. - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: + Copyright [yyyy] [name of copyright owner] - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, + http://www.apache.org/licenses/LICENSE-2.0 - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/Coding_Style.odt b/Coding_Style.odt new file mode 100644 index 0000000000000000000000000000000000000000..23aeef120e2e8a1deb4ce96267a892baf8ad57d0 GIT binary patch literal 23360 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 3] & bytebit[m]) ? 1 : 0; - } - for( i = 0; i < 16; i++ ) { - if( edf == DE1 ) m = (15 - i) << 1; - else m = i << 1; - n = m + 1; - kn[m] = kn[n] = 0L; - for( j = 0; j < 28; j++ ) { - l = j + totrot[i]; - if( l < 28 ) pcr[j] = pc1m[l]; - else pcr[j] = pc1m[l - 28]; - } - for( j = 28; j < 56; j++ ) { - l = j + totrot[i]; - if( l < 56 ) pcr[j] = pc1m[l]; - else pcr[j] = pc1m[l - 28]; - } - for( j = 0; j < 24; j++ ) { - if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; - if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; - } - } - cookey(kn); - return; - } + for ( j = 0; j < 56; j++ ) + { + l = pc1[j]; + m = l & 07; + pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; + } + + for ( i = 0; i < 16; i++ ) + { + if ( edf == DE1 ) + { + m = (15 - i) << 1; + } + else + { + m = i << 1; + } + + n = m + 1; + kn[m] = kn[n] = 0L; + + for ( j = 0; j < 28; j++ ) + { + l = j + totrot[i]; + + if ( l < 28 ) + { + pcr[j] = pc1m[l]; + } + else + { + pcr[j] = pc1m[l - 28]; + } + } + + for ( j = 28; j < 56; j++ ) + { + l = j + totrot[i]; + + if ( l < 56 ) + { + pcr[j] = pc1m[l]; + } + else + { + pcr[j] = pc1m[l - 28]; + } + } + + for ( j = 0; j < 24; j++ ) + { + if ( pcr[pc2[j]] ) + { + kn[m] |= bigbyte[j]; + } + + if ( pcr[pc2[j + 24]] ) + { + kn[n] |= bigbyte[j]; + } + } + } + + cookey(kn); + return; +} static void cookey(register unsigned long *raw1) { - register unsigned long *cook, *raw0; - unsigned long dough[32]; - register int i; + register unsigned long *cook, *raw0; + unsigned long dough[32]; + register int i; - cook = dough; - for( i = 0; i < 16; i++, raw1++ ) { - raw0 = raw1++; - *cook = (*raw0 & 0x00fc0000L) << 6; - *cook |= (*raw0 & 0x00000fc0L) << 10; - *cook |= (*raw1 & 0x00fc0000L) >> 10; - *cook++ |= (*raw1 & 0x00000fc0L) >> 6; - *cook = (*raw0 & 0x0003f000L) << 12; - *cook |= (*raw0 & 0x0000003fL) << 16; - *cook |= (*raw1 & 0x0003f000L) >> 4; - *cook++ |= (*raw1 & 0x0000003fL); - } - rfbUseKey(dough); - return; - } + cook = dough; + + for ( i = 0; i < 16; i++, raw1++ ) + { + raw0 = raw1++; + *cook = (*raw0 & 0x00fc0000L) << 6; + *cook |= (*raw0 & 0x00000fc0L) << 10; + *cook |= (*raw1 & 0x00fc0000L) >> 10; + *cook++ |= (*raw1 & 0x00000fc0L) >> 6; + *cook = (*raw0 & 0x0003f000L) << 12; + *cook |= (*raw0 & 0x0000003fL) << 16; + *cook |= (*raw1 & 0x0003f000L) >> 4; + *cook++ |= (*raw1 & 0x0000003fL); + } + + rfbUseKey(dough); + return; +} void rfbCPKey(register unsigned long *into) { - register unsigned long *from, *endp; + register unsigned long *from, *endp; - from = KnL, endp = &KnL[32]; - while( from < endp ) *into++ = *from++; - return; - } + from = KnL, endp = &KnL[32]; + + while ( from < endp ) + { + *into++ = *from++; + } + + return; +} void rfbUseKey(register unsigned long *from) { - register unsigned long *to, *endp; + register unsigned long *to, *endp; - to = KnL, endp = &KnL[32]; - while( to < endp ) *to++ = *from++; - return; - } + to = KnL, endp = &KnL[32]; + + while ( to < endp ) + { + *to++ = *from++; + } + + return; +} void rfbDes(unsigned char *inblock, unsigned char *outblock) { - unsigned long work[2]; + unsigned long work[2]; - scrunch(inblock, work); - desfunc(work, KnL); - unscrun(work, outblock); - return; - } + scrunch(inblock, work); + desfunc(work, KnL); + unscrun(work, outblock); + return; +} static void scrunch(register unsigned char *outof, register unsigned long *into) { - *into = (*outof++ & 0xffL) << 24; - *into |= (*outof++ & 0xffL) << 16; - *into |= (*outof++ & 0xffL) << 8; - *into++ |= (*outof++ & 0xffL); - *into = (*outof++ & 0xffL) << 24; - *into |= (*outof++ & 0xffL) << 16; - *into |= (*outof++ & 0xffL) << 8; - *into |= (*outof & 0xffL); - return; - } + *into = (*outof++ & 0xffL) << 24; + *into |= (*outof++ & 0xffL) << 16; + *into |= (*outof++ & 0xffL) << 8; + *into++ |= (*outof++ & 0xffL); + *into = (*outof++ & 0xffL) << 24; + *into |= (*outof++ & 0xffL) << 16; + *into |= (*outof++ & 0xffL) << 8; + *into |= (*outof & 0xffL); + return; +} static void unscrun(register unsigned long *outof, register unsigned char *into) { - *into++ = (unsigned char)((*outof >> 24) & 0xffL); - *into++ = (unsigned char)((*outof >> 16) & 0xffL); - *into++ = (unsigned char)((*outof >> 8) & 0xffL); - *into++ = (unsigned char)( *outof++ & 0xffL); - *into++ = (unsigned char)((*outof >> 24) & 0xffL); - *into++ = (unsigned char)((*outof >> 16) & 0xffL); - *into++ = (unsigned char)((*outof >> 8) & 0xffL); - *into = (unsigned char)( *outof & 0xffL); - return; - } + *into++ = (unsigned char)((*outof >> 24) & 0xffL); + *into++ = (unsigned char)((*outof >> 16) & 0xffL); + *into++ = (unsigned char)((*outof >> 8) & 0xffL); + *into++ = (unsigned char)( *outof++ & 0xffL); + *into++ = (unsigned char)((*outof >> 24) & 0xffL); + *into++ = (unsigned char)((*outof >> 16) & 0xffL); + *into++ = (unsigned char)((*outof >> 8) & 0xffL); + *into = (unsigned char)( *outof & 0xffL); + return; +} -static unsigned long SP1[64] = { - 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, - 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, - 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, - 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, - 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, - 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, - 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, - 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, - 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, - 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, - 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, - 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, - 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, - 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, - 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, - 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; - -static unsigned long SP2[64] = { - 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, - 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, - 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, - 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, - 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, - 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, - 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, - 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, - 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, - 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, - 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, - 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, - 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, - 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, - 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, - 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; - -static unsigned long SP3[64] = { - 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, - 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, - 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, - 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, - 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, - 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, - 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, - 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, - 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, - 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, - 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, - 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, - 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, - 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, - 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, - 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; - -static unsigned long SP4[64] = { - 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, - 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, - 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, - 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, - 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, - 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, - 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, - 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, - 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, - 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, - 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, - 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, - 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, - 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, - 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, - 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; - -static unsigned long SP5[64] = { - 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, - 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, - 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, - 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, - 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, - 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, - 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, - 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, - 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, - 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, - 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, - 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, - 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, - 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, - 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, - 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; - -static unsigned long SP6[64] = { - 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, - 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, - 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, - 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, - 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, - 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, - 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, - 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, - 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, - 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, - 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, - 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, - 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, - 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, - 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, - 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; - -static unsigned long SP7[64] = { - 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, - 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, - 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, - 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, - 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, - 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, - 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, - 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, - 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, - 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, - 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, - 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, - 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, - 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, - 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, - 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; - -static unsigned long SP8[64] = { - 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, - 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, - 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, - 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, - 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, - 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, - 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, - 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, - 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, - 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, - 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, - 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, - 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, - 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, - 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, - 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; - -static void desfunc(register unsigned long* block, register unsigned long *keys) +static unsigned long SP1[64] = { - register unsigned long fval, work, right, leftt; - register int round; + 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, + 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, + 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, + 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, + 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, + 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, + 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, + 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, + 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, + 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, + 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, + 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, + 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, + 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L +}; - leftt = block[0]; - right = block[1]; - work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; - right ^= work; - leftt ^= (work << 4); - work = ((leftt >> 16) ^ right) & 0x0000ffffL; - right ^= work; - leftt ^= (work << 16); - work = ((right >> 2) ^ leftt) & 0x33333333L; - leftt ^= work; - right ^= (work << 2); - work = ((right >> 8) ^ leftt) & 0x00ff00ffL; - leftt ^= work; - right ^= (work << 8); - right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; - work = (leftt ^ right) & 0xaaaaaaaaL; - leftt ^= work; - right ^= work; - leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; +static unsigned long SP2[64] = +{ + 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, + 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, + 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, + 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, + 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, + 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, + 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, + 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, + 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, + 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, + 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, + 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, + 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, + 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, + 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, + 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L +}; - for( round = 0; round < 8; round++ ) { - work = (right << 28) | (right >> 4); - work ^= *keys++; - fval = SP7[ work & 0x3fL]; - fval |= SP5[(work >> 8) & 0x3fL]; - fval |= SP3[(work >> 16) & 0x3fL]; - fval |= SP1[(work >> 24) & 0x3fL]; - work = right ^ *keys++; - fval |= SP8[ work & 0x3fL]; - fval |= SP6[(work >> 8) & 0x3fL]; - fval |= SP4[(work >> 16) & 0x3fL]; - fval |= SP2[(work >> 24) & 0x3fL]; - leftt ^= fval; - work = (leftt << 28) | (leftt >> 4); - work ^= *keys++; - fval = SP7[ work & 0x3fL]; - fval |= SP5[(work >> 8) & 0x3fL]; - fval |= SP3[(work >> 16) & 0x3fL]; - fval |= SP1[(work >> 24) & 0x3fL]; - work = leftt ^ *keys++; - fval |= SP8[ work & 0x3fL]; - fval |= SP6[(work >> 8) & 0x3fL]; - fval |= SP4[(work >> 16) & 0x3fL]; - fval |= SP2[(work >> 24) & 0x3fL]; - right ^= fval; - } +static unsigned long SP3[64] = +{ + 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, + 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, + 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, + 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, + 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, + 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, + 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, + 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, + 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, + 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, + 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, + 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, + 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, + 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, + 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, + 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L +}; - right = (right << 31) | (right >> 1); - work = (leftt ^ right) & 0xaaaaaaaaL; - leftt ^= work; - right ^= work; - leftt = (leftt << 31) | (leftt >> 1); - work = ((leftt >> 8) ^ right) & 0x00ff00ffL; - right ^= work; - leftt ^= (work << 8); - work = ((leftt >> 2) ^ right) & 0x33333333L; - right ^= work; - leftt ^= (work << 2); - work = ((right >> 16) ^ leftt) & 0x0000ffffL; - leftt ^= work; - right ^= (work << 16); - work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; - leftt ^= work; - right ^= (work << 4); - *block++ = right; - *block = leftt; - return; - } +static unsigned long SP4[64] = +{ + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, + 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, + 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, + 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, + 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, + 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, + 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, + 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, + 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L +}; + +static unsigned long SP5[64] = +{ + 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, + 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, + 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, + 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, + 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, + 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, + 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, + 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, + 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, + 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, + 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, + 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, + 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, + 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, + 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, + 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L +}; + +static unsigned long SP6[64] = +{ + 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, + 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, + 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, + 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, + 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, + 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, + 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, + 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, + 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, + 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, + 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, + 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, + 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, + 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L +}; + +static unsigned long SP7[64] = +{ + 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, + 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, + 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, + 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, + 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, + 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, + 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, + 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, + 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, + 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, + 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, + 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, + 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, + 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, + 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, + 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L +}; + +static unsigned long SP8[64] = +{ + 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, + 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, + 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, + 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, + 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, + 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, + 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, + 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, + 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, + 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, + 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, + 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, + 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, + 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, + 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, + 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L +}; + +static void desfunc(register unsigned long *block, register unsigned long *keys) +{ + register unsigned long fval, work, right, leftt; + register int round; + + leftt = block[0]; + right = block[1]; + work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; + right ^= work; + leftt ^= (work << 4); + work = ((leftt >> 16) ^ right) & 0x0000ffffL; + right ^= work; + leftt ^= (work << 16); + work = ((right >> 2) ^ leftt) & 0x33333333L; + leftt ^= work; + right ^= (work << 2); + work = ((right >> 8) ^ leftt) & 0x00ff00ffL; + leftt ^= work; + right ^= (work << 8); + right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; + work = (leftt ^ right) & 0xaaaaaaaaL; + leftt ^= work; + right ^= work; + leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; + + for ( round = 0; round < 8; round++ ) + { + work = (right << 28) | (right >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = right ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + leftt ^= fval; + work = (leftt << 28) | (leftt >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = leftt ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + right ^= fval; + } + + right = (right << 31) | (right >> 1); + work = (leftt ^ right) & 0xaaaaaaaaL; + leftt ^= work; + right ^= work; + leftt = (leftt << 31) | (leftt >> 1); + work = ((leftt >> 8) ^ right) & 0x00ff00ffL; + right ^= work; + leftt ^= (work << 8); + work = ((leftt >> 2) ^ right) & 0x33333333L; + right ^= work; + leftt ^= (work << 2); + work = ((right >> 16) ^ leftt) & 0x0000ffffL; + leftt ^= work; + right ^= (work << 16); + work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; + leftt ^= work; + right ^= (work << 4); + *block++ = right; + *block = leftt; + return; +} /* Validation sets: * * Single-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef + * Key : 0123 4567 89ab cdef * Plain : 0123 4567 89ab cde7 * Cipher : c957 4425 6a5e d31d * * Double-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 * Plain : 0123 4567 89ab cde7 * Cipher : 7f1d 0a77 826b 8aff * * Double-length key, double-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 * * Triple-length key, single-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 * Plain : 0123 4567 89ab cde7 * Cipher : de0b 7c06 ae5e 0ed5 * * Triple-length key, double-length plaintext - - * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 * diff --git a/common/defines.h b/common/defines.h index 8e2328a7..502a41e8 100644 --- a/common/defines.h +++ b/common/defines.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2009 - - main define/macro file - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * main define/macro file + */ #ifndef DEFINES_H #define DEFINES_H diff --git a/common/file.c b/common/file.c index 808d94dc..c8be7af5 100644 --- a/common/file.c +++ b/common/file.c @@ -1,26 +1,22 @@ -/* - Copyright (c) 2004-2012 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - read a config file -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * read a config file + */ #include "arch.h" #include "os_calls.h" @@ -33,250 +29,276 @@ returns 0 if everything is ok returns 1 if problem reading file */ static int APP_CC -l_file_read_sections(int fd, int max_file_size, struct list* names) +l_file_read_sections(int fd, int max_file_size, struct list *names) { - struct stream* s; - char text[256]; - char c; - int in_it; - int in_it_index; - int len; - int index; - int rv; + struct stream *s; + char text[256]; + char c; + int in_it; + int in_it_index; + int len; + int index; + int rv; - rv = 0; - g_file_seek(fd, 0); - in_it_index = 0; - in_it = 0; - g_memset(text, 0, 256); - list_clear(names); - make_stream(s); - init_stream(s, max_file_size); - len = g_file_read(fd, s->data, max_file_size); - if (len > 0) - { - s->end = s->p + len; - for (index = 0; index < len; index++) + rv = 0; + g_file_seek(fd, 0); + in_it_index = 0; + in_it = 0; + g_memset(text, 0, 256); + list_clear(names); + make_stream(s); + init_stream(s, max_file_size); + len = g_file_read(fd, s->data, max_file_size); + + if (len > 0) { - in_uint8(s, c); - if (c == '[') - { - in_it = 1; - } - else if (c == ']') - { - list_add_item(names, (tbus)g_strdup(text)); - in_it = 0; - in_it_index = 0; - g_memset(text, 0, 256); - } - else if (in_it) - { - text[in_it_index] = c; - in_it_index++; - } + s->end = s->p + len; + + for (index = 0; index < len; index++) + { + in_uint8(s, c); + + if (c == '[') + { + in_it = 1; + } + else if (c == ']') + { + list_add_item(names, (tbus)g_strdup(text)); + in_it = 0; + in_it_index = 0; + g_memset(text, 0, 256); + } + else if (in_it) + { + text[in_it_index] = c; + in_it_index++; + } + } } - } - else if (len < 0) - { - rv = 1; - } - free_stream(s); - return rv; + else if (len < 0) + { + rv = 1; + } + + free_stream(s); + return rv; } /*****************************************************************************/ static int APP_CC -file_read_line(struct stream* s, char* text) +file_read_line(struct stream *s, char *text) { - int i; - int skip_to_end; - int at_end; - char c; - char* hold; + int i; + int skip_to_end; + int at_end; + char c; + char *hold; - skip_to_end = 0; - if (!s_check_rem(s, 1)) - { - return 1; - } - hold = s->p; - i = 0; - in_uint8(s, c); - while (c != 10 && c != 13) - { - if (c == '#' || c == '!' || c == ';') + skip_to_end = 0; + + if (!s_check_rem(s, 1)) { - skip_to_end = 1; + return 1; } - if (!skip_to_end) + + hold = s->p; + i = 0; + in_uint8(s, c); + + while (c != 10 && c != 13) { - text[i] = c; - i++; + if (c == '#' || c == '!' || c == ';') + { + skip_to_end = 1; + } + + if (!skip_to_end) + { + text[i] = c; + i++; + } + + if (s_check_rem(s, 1)) + { + in_uint8(s, c); + } + else + { + c = 0; + break; + } } - if (s_check_rem(s, 1)) + + if (c == 10 || c == 13) { - in_uint8(s, c); + at_end = 0; + + while (c == 10 || c == 13) + { + if (s_check_rem(s, 1)) + { + in_uint8(s, c); + } + else + { + at_end = 1; + break; + } + } + + if (!at_end) + { + s->p--; + } } - else + + text[i] = 0; + + if (text[0] == '[') { - c = 0; - break; + s->p = hold; + return 1; } - } - if (c == 10 || c == 13) - { - at_end = 0; - while (c == 10 || c == 13) - { - if (s_check_rem(s, 1)) - { - in_uint8(s, c); - } - else - { - at_end = 1; - break; - } - } - if (!at_end) - { - s->p--; - } - } - text[i] = 0; - if (text[0] == '[') - { - s->p = hold; - return 1; - } - return 0; + + return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC -file_split_name_value(char* text, char* name, char* value) +file_split_name_value(char *text, char *name, char *value) { - int len; - int i; - int value_index; - int name_index; - int on_to; + int len; + int i; + int value_index; + int name_index; + int on_to; - value_index = 0; - name_index = 0; - on_to = 0; - name[0] = 0; - value[0] = 0; - len = g_strlen(text); - for (i = 0; i < len; i++) - { - if (text[i] == '=') + value_index = 0; + name_index = 0; + on_to = 0; + name[0] = 0; + value[0] = 0; + len = g_strlen(text); + + for (i = 0; i < len; i++) { - on_to = 1; + if (text[i] == '=') + { + on_to = 1; + } + else if (on_to) + { + value[value_index] = text[i]; + value_index++; + value[value_index] = 0; + } + else + { + name[name_index] = text[i]; + name_index++; + name[name_index] = 0; + } } - else if (on_to) - { - value[value_index] = text[i]; - value_index++; - value[value_index] = 0; - } - else - { - name[name_index] = text[i]; - name_index++; - name[name_index] = 0; - } - } - g_strtrim(name, 3); /* trim both right and left */ - g_strtrim(value, 3); /* trim both right and left */ - return 0; + + g_strtrim(name, 3); /* trim both right and left */ + g_strtrim(value, 3); /* trim both right and left */ + return 0; } /*****************************************************************************/ /* return error */ static int APP_CC -l_file_read_section(int fd, int max_file_size, const char* section, - struct list* names, struct list* values) +l_file_read_section(int fd, int max_file_size, const char *section, + struct list *names, struct list *values) { - struct stream* s; - char text[512]; - char name[512]; - char value[512]; - char* lvalue; - char c; - int in_it; - int in_it_index; - int len; - int index; - int file_size; + struct stream *s; + char text[512]; + char name[512]; + char value[512]; + char *lvalue; + char c; + int in_it; + int in_it_index; + int len; + int index; + int file_size; - file_size = 32 * 1024; /* 32 K file size limit */ - g_file_seek(fd, 0); - in_it_index = 0; - in_it = 0; - g_memset(text, 0, 512); - list_clear(names); - list_clear(values); - make_stream(s); - init_stream(s, file_size); - len = g_file_read(fd, s->data, file_size); - if (len > 0) - { - s->end = s->p + len; - for (index = 0; index < len; index++) + file_size = 32 * 1024; /* 32 K file size limit */ + g_file_seek(fd, 0); + in_it_index = 0; + in_it = 0; + g_memset(text, 0, 512); + list_clear(names); + list_clear(values); + make_stream(s); + init_stream(s, file_size); + len = g_file_read(fd, s->data, file_size); + + if (len > 0) { - in_uint8(s, c); - if (c == '[') - { - in_it = 1; - } - else if (c == ']') - { - if (g_strcasecmp(section, text) == 0) + s->end = s->p + len; + + for (index = 0; index < len; index++) { - file_read_line(s, text); - while (file_read_line(s, text) == 0) - { - if (g_strlen(text) > 0) + in_uint8(s, c); + + if (c == '[') { - file_split_name_value(text, name, value); - list_add_item(names, (tbus)g_strdup(name)); - if (value[0] == '$') - { - lvalue = g_getenv(value + 1); - if (lvalue != 0) - { - list_add_item(values, (tbus)g_strdup(lvalue)); - } - else - { - list_add_item(values, (tbus)g_strdup("")); - } - } - else - { - list_add_item(values, (tbus)g_strdup(value)); - } + in_it = 1; + } + else if (c == ']') + { + if (g_strcasecmp(section, text) == 0) + { + file_read_line(s, text); + + while (file_read_line(s, text) == 0) + { + if (g_strlen(text) > 0) + { + file_split_name_value(text, name, value); + list_add_item(names, (tbus)g_strdup(name)); + + if (value[0] == '$') + { + lvalue = g_getenv(value + 1); + + if (lvalue != 0) + { + list_add_item(values, (tbus)g_strdup(lvalue)); + } + else + { + list_add_item(values, (tbus)g_strdup("")); + } + } + else + { + list_add_item(values, (tbus)g_strdup(value)); + } + } + } + + free_stream(s); + return 0; + } + + in_it = 0; + in_it_index = 0; + g_memset(text, 0, 512); + } + else if (in_it) + { + text[in_it_index] = c; + in_it_index++; } - } - free_stream(s); - return 0; } - in_it = 0; - in_it_index = 0; - g_memset(text, 0, 512); - } - else if (in_it) - { - text[in_it_index] = c; - in_it_index++; - } } - } - free_stream(s); - return 1; + + free_stream(s); + return 1; } /*****************************************************************************/ @@ -285,9 +307,9 @@ l_file_read_section(int fd, int max_file_size, const char* section, returns 1 if problem reading file */ /* 32 K file size limit */ int APP_CC -file_read_sections(int fd, struct list* names) +file_read_sections(int fd, struct list *names) { - return l_file_read_sections(fd, 32 * 1024, names); + return l_file_read_sections(fd, 32 * 1024, names); } /*****************************************************************************/ @@ -295,35 +317,39 @@ file_read_sections(int fd, struct list* names) /* this function should be prefered over file_read_sections because it can read any file size */ int APP_CC -file_by_name_read_sections(const char* file_name, struct list* names) +file_by_name_read_sections(const char *file_name, struct list *names) { - int fd; - int file_size; - int rv; + int fd; + int file_size; + int rv; - file_size = g_file_get_size(file_name); - if (file_size < 1) - { - return 1; - } - fd = g_file_open(file_name); - if (fd < 1) - { - return 1; - } - rv = l_file_read_sections(fd, file_size, names); - g_file_close(fd); - return rv; + file_size = g_file_get_size(file_name); + + if (file_size < 1) + { + return 1; + } + + fd = g_file_open(file_name); + + if (fd < 1) + { + return 1; + } + + rv = l_file_read_sections(fd, file_size, names); + g_file_close(fd); + return rv; } /*****************************************************************************/ /* return error */ /* 32 K file size limit */ int APP_CC -file_read_section(int fd, const char* section, - struct list* names, struct list* values) +file_read_section(int fd, const char *section, + struct list *names, struct list *values) { - return l_file_read_section(fd, 32 * 1024, section, names, values); + return l_file_read_section(fd, 32 * 1024, section, names, values); } /*****************************************************************************/ @@ -331,24 +357,28 @@ file_read_section(int fd, const char* section, /* this function should be prefered over file_read_section because it can read any file size */ int APP_CC -file_by_name_read_section(const char* file_name, const char* section, - struct list* names, struct list* values) +file_by_name_read_section(const char *file_name, const char *section, + struct list *names, struct list *values) { - int fd; - int file_size; - int rv; + int fd; + int file_size; + int rv; - file_size = g_file_get_size(file_name); - if (file_size < 1) - { - return 1; - } - fd = g_file_open(file_name); - if (fd < 1) - { - return 1; - } - rv = l_file_read_section(fd, file_size, section, names, values); - g_file_close(fd); - return rv; + file_size = g_file_get_size(file_name); + + if (file_size < 1) + { + return 1; + } + + fd = g_file_open(file_name); + + if (fd < 1) + { + return 1; + } + + rv = l_file_read_section(fd, file_size, section, names, values); + g_file_close(fd); + return rv; } diff --git a/common/file.h b/common/file.h index f5345c4c..c6ce0654 100644 --- a/common/file.h +++ b/common/file.h @@ -1,26 +1,22 @@ -/* - Copyright (c) 2004-2010 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - read a config file -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * read a config file + */ #if !defined(FILE_H) #define FILE_H diff --git a/common/file_loc.h b/common/file_loc.h index acbdd2fc..db312fb4 100644 --- a/common/file_loc.h +++ b/common/file_loc.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - default file locations for log, config, etc - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * default file locations for log, config, etc + */ #if !defined(FILE_LOC_H) #define FILE_LOC_H diff --git a/common/list.c b/common/list.c index f67a08ab..0c27d596 100644 --- a/common/list.c +++ b/common/list.c @@ -1,217 +1,226 @@ -/* - Copyright (c) 2004-2010 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - simple list -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * simple list + */ #include "arch.h" #include "os_calls.h" #include "list.h" /*****************************************************************************/ -struct list* APP_CC +struct list *APP_CC list_create(void) { - struct list* self; + struct list *self; - self = (struct list*)g_malloc(sizeof(struct list), 1); - self->grow_by = 10; - self->alloc_size = 10; - self->items = (tbus*)g_malloc(sizeof(tbus) * 10, 1); - return self; + self = (struct list *)g_malloc(sizeof(struct list), 1); + self->grow_by = 10; + self->alloc_size = 10; + self->items = (tbus *)g_malloc(sizeof(tbus) * 10, 1); + return self; } /*****************************************************************************/ void APP_CC -list_delete(struct list* self) +list_delete(struct list *self) { - int i; + int i; - if (self == 0) - { - return; - } - if (self->auto_free) - { - for (i = 0; i < self->count; i++) + if (self == 0) { - g_free((void*)self->items[i]); - self->items[i] = 0; + return; } - } - g_free(self->items); - g_free(self); + + if (self->auto_free) + { + for (i = 0; i < self->count; i++) + { + g_free((void *)self->items[i]); + self->items[i] = 0; + } + } + + g_free(self->items); + g_free(self); } /*****************************************************************************/ void APP_CC -list_add_item(struct list* self, tbus item) +list_add_item(struct list *self, tbus item) { - tbus* p; - int i; + tbus *p; + int i; - if (self->count >= self->alloc_size) - { - i = self->alloc_size; - self->alloc_size += self->grow_by; - p = (tbus*)g_malloc(sizeof(tbus) * self->alloc_size, 1); - g_memcpy(p, self->items, sizeof(tbus) * i); - g_free(self->items); - self->items = p; - } - self->items[self->count] = item; - self->count++; + if (self->count >= self->alloc_size) + { + i = self->alloc_size; + self->alloc_size += self->grow_by; + p = (tbus *)g_malloc(sizeof(tbus) * self->alloc_size, 1); + g_memcpy(p, self->items, sizeof(tbus) * i); + g_free(self->items); + self->items = p; + } + + self->items[self->count] = item; + self->count++; } /*****************************************************************************/ tbus APP_CC -list_get_item(struct list* self, int index) +list_get_item(struct list *self, int index) { - if (index < 0 || index >= self->count) - { - return 0; - } - return self->items[index]; + if (index < 0 || index >= self->count) + { + return 0; + } + + return self->items[index]; } /*****************************************************************************/ void APP_CC -list_clear(struct list* self) +list_clear(struct list *self) { - int i; + int i; - if (self->auto_free) - { - for (i = 0; i < self->count; i++) + if (self->auto_free) { - g_free((void*)self->items[i]); - self->items[i] = 0; + for (i = 0; i < self->count; i++) + { + g_free((void *)self->items[i]); + self->items[i] = 0; + } } - } - g_free(self->items); - self->count = 0; - self->grow_by = 10; - self->alloc_size = 10; - self->items = (tbus*)g_malloc(sizeof(tbus) * 10, 1); + + g_free(self->items); + self->count = 0; + self->grow_by = 10; + self->alloc_size = 10; + self->items = (tbus *)g_malloc(sizeof(tbus) * 10, 1); } /*****************************************************************************/ int APP_CC -list_index_of(struct list* self, tbus item) +list_index_of(struct list *self, tbus item) { - int i; + int i; - for (i = 0; i < self->count; i++) - { - if (self->items[i] == item) + for (i = 0; i < self->count; i++) { - return i; + if (self->items[i] == item) + { + return i; + } } - } - return -1; + + return -1; } /*****************************************************************************/ void APP_CC -list_remove_item(struct list* self, int index) +list_remove_item(struct list *self, int index) { - int i; + int i; - if (index >= 0 && index < self->count) - { - if (self->auto_free) + if (index >= 0 && index < self->count) { - g_free((void*)self->items[index]); - self->items[index] = 0; + if (self->auto_free) + { + g_free((void *)self->items[index]); + self->items[index] = 0; + } + + for (i = index; i < (self->count - 1); i++) + { + self->items[i] = self->items[i + 1]; + } + + self->count--; } - for (i = index; i < (self->count - 1); i++) - { - self->items[i] = self->items[i + 1]; - } - self->count--; - } } /*****************************************************************************/ void APP_CC -list_insert_item(struct list* self, int index, tbus item) +list_insert_item(struct list *self, int index, tbus item) { - tbus* p; - int i; + tbus *p; + int i; - if (index == self->count) - { - list_add_item(self, item); - return; - } - if (index >= 0 && index < self->count) - { - self->count++; - if (self->count > self->alloc_size) + if (index == self->count) { - i = self->alloc_size; - self->alloc_size += self->grow_by; - p = (tbus*)g_malloc(sizeof(tbus) * self->alloc_size, 1); - g_memcpy(p, self->items, sizeof(tbus) * i); - g_free(self->items); - self->items = p; + list_add_item(self, item); + return; } - for (i = (self->count - 2); i >= index; i--) + + if (index >= 0 && index < self->count) { - self->items[i + 1] = self->items[i]; + self->count++; + + if (self->count > self->alloc_size) + { + i = self->alloc_size; + self->alloc_size += self->grow_by; + p = (tbus *)g_malloc(sizeof(tbus) * self->alloc_size, 1); + g_memcpy(p, self->items, sizeof(tbus) * i); + g_free(self->items); + self->items = p; + } + + for (i = (self->count - 2); i >= index; i--) + { + self->items[i + 1] = self->items[i]; + } + + self->items[index] = item; } - self->items[index] = item; - } } /*****************************************************************************/ /* append one list to another using strdup for each item in the list */ /* begins copy at start_index, a zero based index on the soure list */ void APP_CC -list_append_list_strdup(struct list* self, struct list* dest, int start_index) +list_append_list_strdup(struct list *self, struct list *dest, int start_index) { - int index; - tbus item; - char* dup; + int index; + tbus item; + char *dup; - for (index = start_index; index < self->count; index++) - { - item = list_get_item(self, index); - dup = g_strdup((char*)item); - list_add_item(dest, (tbus)dup); - } + for (index = start_index; index < self->count; index++) + { + item = list_get_item(self, index); + dup = g_strdup((char *)item); + list_add_item(dest, (tbus)dup); + } } /*****************************************************************************/ void APP_CC -list_dump_items(struct list* self) +list_dump_items(struct list *self) { - int index; + int index; - if (self->count == 0) - { - g_writeln("List is empty"); - } - for (index = 0; index < self->count; index++) - { - g_writeln("%d: %s", index, list_get_item(self, index)); - } + if (self->count == 0) + { + g_writeln("List is empty"); + } + + for (index = 0; index < self->count; index++) + { + g_writeln("%d: %s", index, list_get_item(self, index)); + } } diff --git a/common/list.h b/common/list.h index b7cd10b4..2c0f9339 100644 --- a/common/list.h +++ b/common/list.h @@ -1,26 +1,22 @@ -/* - Copyright (c) 2004-2010 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - simple list -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * simple list + */ #if !defined(LIST_H) #define LIST_H diff --git a/common/log.c b/common/log.c index 390b2bff..9b2e9289 100644 --- a/common/log.c +++ b/common/log.c @@ -1,25 +1,20 @@ -/* - Copyright (c) 2005-2012 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include @@ -41,7 +36,7 @@ #include "log.h" /* Here we store the current state and configuration of the log */ -static struct log_config* staticLogConfig = NULL; +static struct log_config *staticLogConfig = NULL; /* This file first start with all private functions. In the end of the file the public functions is defined */ @@ -54,15 +49,17 @@ static struct log_config* staticLogConfig = NULL; * */ int DEFAULT_CC -internal_log_file_open(const char* fname) +internal_log_file_open(const char *fname) { - int ret = -1; - if (fname != NULL) - { - ret = open(fname, O_WRONLY | O_CREAT | O_APPEND | O_SYNC, - S_IRUSR | S_IWUSR); - } - return ret; + int ret = -1; + + if (fname != NULL) + { + ret = open(fname, O_WRONLY | O_CREAT | O_APPEND | O_SYNC, + S_IRUSR | S_IWUSR); + } + + return ret; } /** @@ -75,22 +72,22 @@ internal_log_file_open(const char* fname) int DEFAULT_CC internal_log_xrdp2syslog(const enum logLevels lvl) { - switch (lvl) - { - case LOG_LEVEL_ALWAYS: - return LOG_CRIT; - case LOG_LEVEL_ERROR: - return LOG_ERR; - case LOG_LEVEL_WARNING: - return LOG_WARNING; - case LOG_LEVEL_INFO: - return LOG_INFO; - case LOG_LEVEL_DEBUG: - return LOG_DEBUG; - default: - g_writeln("Undefined log level - programming error"); - return LOG_DEBUG; - } + switch (lvl) + { + case LOG_LEVEL_ALWAYS: + return LOG_CRIT; + case LOG_LEVEL_ERROR: + return LOG_ERR; + case LOG_LEVEL_WARNING: + return LOG_WARNING; + case LOG_LEVEL_INFO: + return LOG_INFO; + case LOG_LEVEL_DEBUG: + return LOG_DEBUG; + default: + g_writeln("Undefined log level - programming error"); + return LOG_DEBUG; + } } /** @@ -101,117 +98,121 @@ internal_log_xrdp2syslog(const enum logLevels lvl) * */ void DEFAULT_CC -internal_log_lvl2str(const enum logLevels lvl, char* str) +internal_log_lvl2str(const enum logLevels lvl, char *str) { - switch (lvl) - { - case LOG_LEVEL_ALWAYS: - snprintf(str, 9, "%s", "[CORE ] "); - break; - case LOG_LEVEL_ERROR: - snprintf(str, 9, "%s", "[ERROR] "); - break; - case LOG_LEVEL_WARNING: - snprintf(str, 9, "%s", "[WARN ] "); - break; - case LOG_LEVEL_INFO: - snprintf(str, 9, "%s", "[INFO ] "); - break; - case LOG_LEVEL_DEBUG: - snprintf(str, 9, "%s", "[DEBUG] "); - break; - default: - snprintf(str, 9, "%s", "PRG ERR!"); - g_writeln("Programming error - undefined log level!!!"); - } + switch (lvl) + { + case LOG_LEVEL_ALWAYS: + snprintf(str, 9, "%s", "[CORE ] "); + break; + case LOG_LEVEL_ERROR: + snprintf(str, 9, "%s", "[ERROR] "); + break; + case LOG_LEVEL_WARNING: + snprintf(str, 9, "%s", "[WARN ] "); + break; + case LOG_LEVEL_INFO: + snprintf(str, 9, "%s", "[INFO ] "); + break; + case LOG_LEVEL_DEBUG: + snprintf(str, 9, "%s", "[DEBUG] "); + break; + default: + snprintf(str, 9, "%s", "PRG ERR!"); + g_writeln("Programming error - undefined log level!!!"); + } } /******************************************************************************/ enum logReturns DEFAULT_CC -internal_log_start(struct log_config* l_cfg) +internal_log_start(struct log_config *l_cfg) { - enum logReturns ret = LOG_GENERAL_ERROR; - if (0 == l_cfg) - { - ret = LOG_ERROR_MALLOC; - return ret; - } + enum logReturns ret = LOG_GENERAL_ERROR; - /* if logfile is NULL, we return error */ - if (0 == l_cfg->log_file) - { - g_writeln("log_file not properly assigned"); - return ret; - } + if (0 == l_cfg) + { + ret = LOG_ERROR_MALLOC; + return ret; + } - /* if progname is NULL, we ureturn error */ - if (0 == l_cfg->program_name) - { - g_writeln("program_name not properly assigned"); - return ret; - } + /* if logfile is NULL, we return error */ + if (0 == l_cfg->log_file) + { + g_writeln("log_file not properly assigned"); + return ret; + } - /* open file */ - l_cfg->fd = internal_log_file_open(l_cfg->log_file); + /* if progname is NULL, we ureturn error */ + if (0 == l_cfg->program_name) + { + g_writeln("program_name not properly assigned"); + return ret; + } - if (-1 == l_cfg->fd) - { - return LOG_ERROR_FILE_OPEN; - } + /* open file */ + l_cfg->fd = internal_log_file_open(l_cfg->log_file); - /* if syslog is enabled, open it */ - if (l_cfg->enable_syslog) - { - openlog(l_cfg->program_name, LOG_CONS | LOG_PID, LOG_DAEMON); - } + if (-1 == l_cfg->fd) + { + return LOG_ERROR_FILE_OPEN; + } + + /* if syslog is enabled, open it */ + if (l_cfg->enable_syslog) + { + openlog(l_cfg->program_name, LOG_CONS | LOG_PID, LOG_DAEMON); + } #ifdef LOG_ENABLE_THREAD - pthread_mutexattr_init(&(l_cfg->log_lock_attr)); - pthread_mutex_init(&(l_cfg->log_lock), &(l_cfg->log_lock_attr)); + pthread_mutexattr_init(&(l_cfg->log_lock_attr)); + pthread_mutex_init(&(l_cfg->log_lock), &(l_cfg->log_lock_attr)); #endif - return LOG_STARTUP_OK; + return LOG_STARTUP_OK; } /******************************************************************************/ enum logReturns DEFAULT_CC -internal_log_end(struct log_config* l_cfg) +internal_log_end(struct log_config *l_cfg) { - enum logReturns ret = LOG_GENERAL_ERROR; - /* if log is closed, quit silently */ - if (0 == l_cfg) - { + enum logReturns ret = LOG_GENERAL_ERROR; + + /* if log is closed, quit silently */ + if (0 == l_cfg) + { + return ret; + } + + /* closing log file */ + log_message(LOG_LEVEL_ALWAYS, "shutting down log subsystem..."); + + if (0 > l_cfg->fd) + { + /* closing logfile... */ + g_file_close(l_cfg->fd); + } + + /* if syslog is enabled, close it */ + if (l_cfg->enable_syslog) + { + closelog(); + } + + /* freeing allocated memory */ + if (0 != l_cfg->log_file) + { + g_free(l_cfg->log_file); + l_cfg->log_file = 0; + } + + if (0 != l_cfg->program_name) + { + g_free(l_cfg->program_name); + l_cfg->program_name = 0; + } + + ret = LOG_STARTUP_OK; return ret; - } - - /* closing log file */ - log_message(LOG_LEVEL_ALWAYS, "shutting down log subsystem..."); - - if (0 > l_cfg->fd) - { - /* closing logfile... */ - g_file_close(l_cfg->fd); - } - - /* if syslog is enabled, close it */ - if (l_cfg->enable_syslog) - { - closelog(); - } - - /* freeing allocated memory */ - if (0 != l_cfg->log_file) - { - g_free(l_cfg->log_file); - l_cfg->log_file = 0; - } - if (0 != l_cfg->program_name) - { - g_free(l_cfg->program_name); - l_cfg->program_name = 0; - } - ret = LOG_STARTUP_OK; - return ret; } /** @@ -220,177 +221,192 @@ internal_log_end(struct log_config* l_cfg) * @return */ enum logLevels DEFAULT_CC -internal_log_text2level(char* buf) +internal_log_text2level(char *buf) { - if (0 == g_strcasecmp(buf, "0") || - 0 == g_strcasecmp(buf, "core")) - { - return LOG_LEVEL_ALWAYS; - } - else if (0 == g_strcasecmp(buf, "1") || - 0 == g_strcasecmp(buf, "error")) - { - return LOG_LEVEL_ERROR; - } - else if (0 == g_strcasecmp(buf, "2") || - 0 == g_strcasecmp(buf, "warn") || - 0 == g_strcasecmp(buf, "warning")) - { - return LOG_LEVEL_WARNING; - } - else if (0 == g_strcasecmp(buf, "3") || - 0 == g_strcasecmp(buf, "info")) - { - return LOG_LEVEL_INFO; - } - else if (0 == g_strcasecmp(buf, "4") || - 0 == g_strcasecmp(buf, "debug")) - { + if (0 == g_strcasecmp(buf, "0") || + 0 == g_strcasecmp(buf, "core")) + { + return LOG_LEVEL_ALWAYS; + } + else if (0 == g_strcasecmp(buf, "1") || + 0 == g_strcasecmp(buf, "error")) + { + return LOG_LEVEL_ERROR; + } + else if (0 == g_strcasecmp(buf, "2") || + 0 == g_strcasecmp(buf, "warn") || + 0 == g_strcasecmp(buf, "warning")) + { + return LOG_LEVEL_WARNING; + } + else if (0 == g_strcasecmp(buf, "3") || + 0 == g_strcasecmp(buf, "info")) + { + return LOG_LEVEL_INFO; + } + else if (0 == g_strcasecmp(buf, "4") || + 0 == g_strcasecmp(buf, "debug")) + { + return LOG_LEVEL_DEBUG; + } + + g_writeln("Your configured log level is corrupt - we use debug log level"); return LOG_LEVEL_DEBUG; - } - g_writeln("Your configured log level is corrupt - we use debug log level"); - return LOG_LEVEL_DEBUG; } enum logReturns DEFAULT_CC -internalReadConfiguration(const char* inFilename, const char* applicationName) +internalReadConfiguration(const char *inFilename, const char *applicationName) { - int fd; - enum logReturns ret = LOG_GENERAL_ERROR; - struct list* sec; - struct list* param_n; - struct list* param_v; + int fd; + enum logReturns ret = LOG_GENERAL_ERROR; + struct list *sec; + struct list *param_n; + struct list *param_v; - if (inFilename == NULL) - { - g_writeln("The inifile is null to readConfiguration!"); - return ret; - } - fd = g_file_open(inFilename); - if (-1 == fd) - { - ret = LOG_ERROR_NO_CFG; - g_writeln("We could not open the configuration file to read log parameters"); - return ret; - } - /* we initialize the memory for the configuration and set all content - to zero. */ - ret = internalInitAndAllocStruct(); - if (ret != LOG_STARTUP_OK) - { - return ret; - } + if (inFilename == NULL) + { + g_writeln("The inifile is null to readConfiguration!"); + return ret; + } - sec = list_create(); - sec->auto_free = 1; - file_read_sections(fd, sec); - param_n = list_create(); - param_n->auto_free = 1; - param_v = list_create(); - param_v->auto_free = 1; + fd = g_file_open(inFilename); - /* read logging config */ - ret = internal_config_read_logging(fd, staticLogConfig, param_n, - param_v, applicationName); - if (ret != LOG_STARTUP_OK) - { + if (-1 == fd) + { + ret = LOG_ERROR_NO_CFG; + g_writeln("We could not open the configuration file to read log parameters"); + return ret; + } + + /* we initialize the memory for the configuration and set all content + to zero. */ + ret = internalInitAndAllocStruct(); + + if (ret != LOG_STARTUP_OK) + { + return ret; + } + + sec = list_create(); + sec->auto_free = 1; + file_read_sections(fd, sec); + param_n = list_create(); + param_n->auto_free = 1; + param_v = list_create(); + param_v->auto_free = 1; + + /* read logging config */ + ret = internal_config_read_logging(fd, staticLogConfig, param_n, + param_v, applicationName); + + if (ret != LOG_STARTUP_OK) + { + return ret; + } + + /* cleanup */ + list_delete(sec); + list_delete(param_v); + list_delete(param_n); + g_file_close(fd); return ret; - } - /* cleanup */ - list_delete(sec); - list_delete(param_v); - list_delete(param_n); - g_file_close(fd); - return ret; } /******************************************************************************/ enum logReturns DEFAULT_CC -internal_config_read_logging(int file, struct log_config* lc, - struct list* param_n, - struct list* param_v, - const char* applicationName) +internal_config_read_logging(int file, struct log_config *lc, + struct list *param_n, + struct list *param_v, + const char *applicationName) { - int i; - char* buf; - char* temp_buf; + int i; + char *buf; + char *temp_buf; - list_clear(param_v); - list_clear(param_n); + list_clear(param_v); + list_clear(param_n); - /* setting defaults */ - lc->program_name = g_strdup(applicationName); - lc->log_file = 0; - lc->fd = 0; - lc->log_level = LOG_LEVEL_DEBUG; - lc->enable_syslog = 0; - lc->syslog_level = LOG_LEVEL_DEBUG; + /* setting defaults */ + lc->program_name = g_strdup(applicationName); + lc->log_file = 0; + lc->fd = 0; + lc->log_level = LOG_LEVEL_DEBUG; + lc->enable_syslog = 0; + lc->syslog_level = LOG_LEVEL_DEBUG; - file_read_section(file, SESMAN_CFG_LOGGING, param_n, param_v); - for (i = 0; i < param_n->count; i++) - { - buf = (char*)list_get_item(param_n, i); - if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_FILE)) + file_read_section(file, SESMAN_CFG_LOGGING, param_n, param_v); + + for (i = 0; i < param_n->count; i++) { - lc->log_file = g_strdup((char*)list_get_item(param_v, i)); - if (lc->log_file != NULL) - { - if (lc->log_file[0] != '/') + buf = (char *)list_get_item(param_n, i); + + if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_FILE)) { - temp_buf = (char*)g_malloc(512, 0); - g_snprintf(temp_buf, 511, "%s/%s", XRDP_LOG_PATH, lc->log_file); - g_free(lc->log_file); - lc->log_file = temp_buf; + lc->log_file = g_strdup((char *)list_get_item(param_v, i)); + + if (lc->log_file != NULL) + { + if (lc->log_file[0] != '/') + { + temp_buf = (char *)g_malloc(512, 0); + g_snprintf(temp_buf, 511, "%s/%s", XRDP_LOG_PATH, lc->log_file); + g_free(lc->log_file); + lc->log_file = temp_buf; + } + } } - } - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_LEVEL)) - { - lc->log_level = internal_log_text2level((char*)list_get_item(param_v, i)); - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG)) - { - lc->enable_syslog = text2bool((char*)list_get_item(param_v, i)); - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL)) - { - lc->syslog_level = internal_log_text2level((char*)list_get_item(param_v, i)); - } - } - if (0 == lc->log_file) - { - lc->log_file = g_strdup("./sesman.log"); - } + if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_LEVEL)) + { + lc->log_level = internal_log_text2level((char *)list_get_item(param_v, i)); + } - /* try to create path if not exist */ - g_create_path(lc->log_file); + if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_ENABLE_SYSLOG)) + { + lc->enable_syslog = text2bool((char *)list_get_item(param_v, i)); + } - g_printf("logging configuration:\r\n"); - g_printf("\tLogFile: %s\r\n", lc->log_file); - g_printf("\tLogLevel: %i\r\n", lc->log_level); - g_printf("\tEnableSyslog: %i\r\n", lc->enable_syslog); - g_printf("\tSyslogLevel: %i\r\n", lc->syslog_level); - return LOG_STARTUP_OK; + if (0 == g_strcasecmp(buf, SESMAN_CFG_LOG_SYSLOG_LEVEL)) + { + lc->syslog_level = internal_log_text2level((char *)list_get_item(param_v, i)); + } + } + + if (0 == lc->log_file) + { + lc->log_file = g_strdup("./sesman.log"); + } + + /* try to create path if not exist */ + g_create_path(lc->log_file); + + g_printf("logging configuration:\r\n"); + g_printf("\tLogFile: %s\r\n", lc->log_file); + g_printf("\tLogLevel: %i\r\n", lc->log_level); + g_printf("\tEnableSyslog: %i\r\n", lc->enable_syslog); + g_printf("\tSyslogLevel: %i\r\n", lc->syslog_level); + return LOG_STARTUP_OK; } enum logReturns DEFAULT_CC internalInitAndAllocStruct(void) { - enum logReturns ret = LOG_GENERAL_ERROR; - staticLogConfig = g_malloc(sizeof(struct log_config), 1); - if (staticLogConfig != NULL) - { - staticLogConfig->fd = -1; - staticLogConfig->enable_syslog = 0; - ret = LOG_STARTUP_OK; - } - else - { - g_writeln("could not allocate memory for log struct"); - ret = LOG_ERROR_MALLOC; - } - return ret; + enum logReturns ret = LOG_GENERAL_ERROR; + staticLogConfig = g_malloc(sizeof(struct log_config), 1); + + if (staticLogConfig != NULL) + { + staticLogConfig->fd = -1; + staticLogConfig->enable_syslog = 0; + ret = LOG_STARTUP_OK; + } + else + { + g_writeln("could not allocate memory for log struct"); + ret = LOG_ERROR_MALLOC; + } + + return ret; } /* @@ -406,60 +422,68 @@ internalInitAndAllocStruct(void) * */ int APP_CC -text2bool(char* s) +text2bool(char *s) { - if (0 == g_strcasecmp(s, "1") || - 0 == g_strcasecmp(s, "true") || - 0 == g_strcasecmp(s, "yes")) - { - return 1; - } - return 0; + if (0 == g_strcasecmp(s, "1") || + 0 == g_strcasecmp(s, "true") || + 0 == g_strcasecmp(s, "yes")) + { + return 1; + } + + return 0; } enum logReturns DEFAULT_CC -log_start_from_param(const struct log_config* iniParams) +log_start_from_param(const struct log_config *iniParams) { - enum logReturns ret = LOG_GENERAL_ERROR; - if (staticLogConfig != NULL) - { - log_message(LOG_LEVEL_ALWAYS, "Log already initialized"); - return ret; - } - if (iniParams == NULL) - { - g_writeln("inparam to log_start_from_param is NULL"); - return ret; - } - else - { - /*Copy the struct information*/ - ret = internalInitAndAllocStruct(); - if (ret != LOG_STARTUP_OK) + enum logReturns ret = LOG_GENERAL_ERROR; + + if (staticLogConfig != NULL) { - g_writeln("internalInitAndAllocStruct failed"); - return ret; + log_message(LOG_LEVEL_ALWAYS, "Log already initialized"); + return ret; } - staticLogConfig->enable_syslog = iniParams->enable_syslog; - staticLogConfig->fd = iniParams->fd; - staticLogConfig->log_file = g_strdup(iniParams->log_file); - staticLogConfig->log_level = iniParams->log_level; - staticLogConfig->log_lock = iniParams->log_lock; - staticLogConfig->log_lock_attr = iniParams->log_lock_attr; - staticLogConfig->program_name = g_strdup(iniParams->program_name); - staticLogConfig->syslog_level = iniParams->syslog_level; - ret = internal_log_start(staticLogConfig); - if (ret != LOG_STARTUP_OK) + + if (iniParams == NULL) { - g_writeln("Could not start log"); - if (staticLogConfig != NULL) - { - g_free(staticLogConfig); - staticLogConfig = NULL; - } + g_writeln("inparam to log_start_from_param is NULL"); + return ret; } - } - return ret; + else + { + /*Copy the struct information*/ + ret = internalInitAndAllocStruct(); + + if (ret != LOG_STARTUP_OK) + { + g_writeln("internalInitAndAllocStruct failed"); + return ret; + } + + staticLogConfig->enable_syslog = iniParams->enable_syslog; + staticLogConfig->fd = iniParams->fd; + staticLogConfig->log_file = g_strdup(iniParams->log_file); + staticLogConfig->log_level = iniParams->log_level; + staticLogConfig->log_lock = iniParams->log_lock; + staticLogConfig->log_lock_attr = iniParams->log_lock_attr; + staticLogConfig->program_name = g_strdup(iniParams->program_name); + staticLogConfig->syslog_level = iniParams->syslog_level; + ret = internal_log_start(staticLogConfig); + + if (ret != LOG_STARTUP_OK) + { + g_writeln("Could not start log"); + + if (staticLogConfig != NULL) + { + g_free(staticLogConfig); + staticLogConfig = NULL; + } + } + } + + return ret; } /** @@ -470,34 +494,40 @@ log_start_from_param(const struct log_config* iniParams) * @return 0 on success */ enum logReturns DEFAULT_CC -log_start(const char* iniFile, const char* applicationName) +log_start(const char *iniFile, const char *applicationName) { - enum logReturns ret = LOG_GENERAL_ERROR; - if (applicationName == NULL) - { - g_writeln("Programming error your application name cannot be null"); - return ret; - } - ret = internalReadConfiguration(iniFile, applicationName); - if (ret == LOG_STARTUP_OK) - { - ret = internal_log_start(staticLogConfig); - if (ret != LOG_STARTUP_OK) + enum logReturns ret = LOG_GENERAL_ERROR; + + if (applicationName == NULL) { - g_writeln("Could not start log"); - if (staticLogConfig != NULL) - { - g_free(staticLogConfig); - staticLogConfig = NULL; - } + g_writeln("Programming error your application name cannot be null"); + return ret; } - } - else - { - g_writeln("Error reading configuration for log based on config: %s", - iniFile); - } - return ret; + + ret = internalReadConfiguration(iniFile, applicationName); + + if (ret == LOG_STARTUP_OK) + { + ret = internal_log_start(staticLogConfig); + + if (ret != LOG_STARTUP_OK) + { + g_writeln("Could not start log"); + + if (staticLogConfig != NULL) + { + g_free(staticLogConfig); + staticLogConfig = NULL; + } + } + } + else + { + g_writeln("Error reading configuration for log based on config: %s", + iniFile); + } + + return ret; } /** @@ -507,123 +537,132 @@ log_start(const char* iniFile, const char* applicationName) enum logReturns DEFAULT_CC log_end(void) { - enum logReturns ret = LOG_GENERAL_ERROR; - ret = internal_log_end(staticLogConfig); - if (staticLogConfig != NULL) - { - g_free(staticLogConfig); - staticLogConfig = NULL; - } - return ret; + enum logReturns ret = LOG_GENERAL_ERROR; + ret = internal_log_end(staticLogConfig); + + if (staticLogConfig != NULL) + { + g_free(staticLogConfig); + staticLogConfig = NULL; + } + + return ret; } enum logReturns DEFAULT_CC -log_message(const enum logLevels lvl, const char* msg, ...) +log_message(const enum logLevels lvl, const char *msg, ...) { - char buff[LOG_BUFFER_SIZE + 31]; /* 19 (datetime) 4 (space+cr+lf+\0) */ - va_list ap; - int len = 0; - enum logReturns rv = LOG_STARTUP_OK; - int writereply = 0; - time_t now_t; - struct tm* now; - if (staticLogConfig == NULL) - { - g_writeln("The log reference is NULL - log not initialized properly"); - return LOG_ERROR_NO_CFG; - } - if (0 > staticLogConfig->fd && staticLogConfig->enable_syslog == 0) - { - return LOG_ERROR_FILE_NOT_OPEN; - } + char buff[LOG_BUFFER_SIZE + 31]; /* 19 (datetime) 4 (space+cr+lf+\0) */ + va_list ap; + int len = 0; + enum logReturns rv = LOG_STARTUP_OK; + int writereply = 0; + time_t now_t; + struct tm *now; - now_t = time(&now_t); - now = localtime(&now_t); + if (staticLogConfig == NULL) + { + g_writeln("The log reference is NULL - log not initialized properly"); + return LOG_ERROR_NO_CFG; + } - snprintf(buff, 21, "[%.4d%.2d%.2d-%.2d:%.2d:%.2d] ", now->tm_year + 1900, - now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, - now->tm_sec); + if (0 > staticLogConfig->fd && staticLogConfig->enable_syslog == 0) + { + return LOG_ERROR_FILE_NOT_OPEN; + } - internal_log_lvl2str(lvl, buff + 20); + now_t = time(&now_t); + now = localtime(&now_t); - va_start(ap, msg); - len = vsnprintf(buff + 28, LOG_BUFFER_SIZE, msg, ap); - va_end(ap); + snprintf(buff, 21, "[%.4d%.2d%.2d-%.2d:%.2d:%.2d] ", now->tm_year + 1900, + now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, + now->tm_sec); - /* checking for truncated messages */ - if (len > LOG_BUFFER_SIZE) - { - log_message(LOG_LEVEL_WARNING, "next message will be truncated"); - } + internal_log_lvl2str(lvl, buff + 20); - /* forcing the end of message string */ + va_start(ap, msg); + len = vsnprintf(buff + 28, LOG_BUFFER_SIZE, msg, ap); + va_end(ap); + + /* checking for truncated messages */ + if (len > LOG_BUFFER_SIZE) + { + log_message(LOG_LEVEL_WARNING, "next message will be truncated"); + } + + /* forcing the end of message string */ #ifdef _WIN32 - buff[len + 28] = '\r'; - buff[len + 29] = '\n'; - buff[len + 30] = '\0'; + buff[len + 28] = '\r'; + buff[len + 29] = '\n'; + buff[len + 30] = '\0'; #else #ifdef _MACOS - buff[len + 28] = '\r'; - buff[len + 29] = '\0'; + buff[len + 28] = '\r'; + buff[len + 29] = '\0'; #else - buff[len + 28] = '\n'; - buff[len + 29] = '\0'; + buff[len + 28] = '\n'; + buff[len + 29] = '\0'; #endif #endif - if (staticLogConfig->enable_syslog && (lvl <= staticLogConfig->syslog_level)) - { - /* log to syslog*/ - /* %s fix compiler warning 'not a string literal' */ - syslog(internal_log_xrdp2syslog(lvl), "(%d)(%ld)%s", g_getpid(), - tc_get_threadid(), buff + 20); - } - - if (lvl <= staticLogConfig->log_level) - { - /* log to console */ - g_printf(buff); - - /* log to application logfile */ -#ifdef LOG_ENABLE_THREAD - pthread_mutex_lock(&(staticLogConfig->log_lock)); -#endif - if (staticLogConfig->fd > 0) + if (staticLogConfig->enable_syslog && (lvl <= staticLogConfig->syslog_level)) { - writereply = g_file_write(staticLogConfig->fd, buff, g_strlen(buff)); - if (writereply <= 0) - { - rv = LOG_ERROR_NULL_FILE; - } + /* log to syslog*/ + /* %s fix compiler warning 'not a string literal' */ + syslog(internal_log_xrdp2syslog(lvl), "(%d)(%ld)%s", g_getpid(), + tc_get_threadid(), buff + 20); } + + if (lvl <= staticLogConfig->log_level) + { + /* log to console */ + g_printf(buff); + + /* log to application logfile */ #ifdef LOG_ENABLE_THREAD - pthread_mutex_unlock(&(staticLogConfig->log_lock)); + pthread_mutex_lock(&(staticLogConfig->log_lock)); #endif - } - return rv; + + if (staticLogConfig->fd > 0) + { + writereply = g_file_write(staticLogConfig->fd, buff, g_strlen(buff)); + + if (writereply <= 0) + { + rv = LOG_ERROR_NULL_FILE; + } + } + +#ifdef LOG_ENABLE_THREAD + pthread_mutex_unlock(&(staticLogConfig->log_lock)); +#endif + } + + return rv; } /** * Return the configured log file name * @return */ -char* DEFAULT_CC -getLogFile(char* replybuf, int bufsize) +char *DEFAULT_CC +getLogFile(char *replybuf, int bufsize) { - if (staticLogConfig) - { - if (staticLogConfig->log_file) + if (staticLogConfig) { - g_strncpy(replybuf, staticLogConfig->log_file, bufsize); + if (staticLogConfig->log_file) + { + g_strncpy(replybuf, staticLogConfig->log_file, bufsize); + } + else + { + g_sprintf(replybuf, "The log_file name is NULL"); + } } else { - g_sprintf(replybuf, "The log_file name is NULL"); + g_snprintf(replybuf, bufsize, "The log is not properly started"); } - } - else - { - g_snprintf(replybuf, bufsize, "The log is not properly started"); - } - return replybuf; + + return replybuf; } diff --git a/common/log.h b/common/log.h index cc355b18..c83a34d3 100644 --- a/common/log.h +++ b/common/log.h @@ -1,25 +1,20 @@ -/* - Copyright (c) 2005-2012 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef LOG_H #define LOG_H diff --git a/common/os_calls.c b/common/os_calls.c index 6b55f2f7..20c84f3e 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -1,28 +1,24 @@ -/* - Copyright (c) 2004-2012 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - generic operating system calls - - put all the os / arch define in here you want -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * generic operating system calls + * + * put all the os / arch define in here you want + */ #if defined(HAVE_CONFIG_H) #include "config_ac.h" @@ -68,7 +64,7 @@ /* for clearenv() */ #if defined(_WIN32) #else -extern char** environ; +extern char **environ; #endif #if defined(__linux__) @@ -90,77 +86,85 @@ static char g_temp_base_org[128] = ""; int APP_CC g_rm_temp_dir(void) { - if (g_temp_base[0] != 0) - { - if (!g_remove_dir(g_temp_base)) + if (g_temp_base[0] != 0) { - printf("g_rm_temp_dir: removing temp directory [%s] failed\n", g_temp_base); + if (!g_remove_dir(g_temp_base)) + { + printf("g_rm_temp_dir: removing temp directory [%s] failed\n", g_temp_base); + } + + g_temp_base[0] = 0; } - g_temp_base[0] = 0; - } - return 0; + + return 0; } /*****************************************************************************/ int APP_CC -g_mk_temp_dir(const char* app_name) +g_mk_temp_dir(const char *app_name) { - if (app_name != 0) - { - if (app_name[0] != 0) + if (app_name != 0) { - if (!g_directory_exist("/tmp/.xrdp")) - { - if (!g_create_dir("/tmp/.xrdp")) + if (app_name[0] != 0) { - printf("g_mk_temp_dir: g_create_dir failed\n"); - return 1; + if (!g_directory_exist("/tmp/.xrdp")) + { + if (!g_create_dir("/tmp/.xrdp")) + { + printf("g_mk_temp_dir: g_create_dir failed\n"); + return 1; + } + + g_chmod_hex("/tmp/.xrdp", 0x1777); + } + + snprintf(g_temp_base, sizeof(g_temp_base), + "/tmp/.xrdp/%s-XXXXXX", app_name); + snprintf(g_temp_base_org, sizeof(g_temp_base_org), + "/tmp/.xrdp/%s-XXXXXX", app_name); + + if (mkdtemp(g_temp_base) == 0) + { + printf("g_mk_temp_dir: mkdtemp failed [%s]\n", g_temp_base); + return 1; + } + } + else + { + printf("g_mk_temp_dir: bad app name\n"); + return 1; } - g_chmod_hex("/tmp/.xrdp", 0x1777); - } - snprintf(g_temp_base, sizeof(g_temp_base), - "/tmp/.xrdp/%s-XXXXXX", app_name); - snprintf(g_temp_base_org, sizeof(g_temp_base_org), - "/tmp/.xrdp/%s-XXXXXX", app_name); - if (mkdtemp(g_temp_base) == 0) - { - printf("g_mk_temp_dir: mkdtemp failed [%s]\n", g_temp_base); - return 1; - } } else { - printf("g_mk_temp_dir: bad app name\n"); - return 1; + if (g_temp_base_org[0] == 0) + { + printf("g_mk_temp_dir: g_temp_base_org not set\n"); + return 1; + } + + g_strncpy(g_temp_base, g_temp_base_org, 127); + + if (mkdtemp(g_temp_base) == 0) + { + printf("g_mk_temp_dir: mkdtemp failed [%s]\n", g_temp_base); + } } - } - else - { - if (g_temp_base_org[0] == 0) - { - printf("g_mk_temp_dir: g_temp_base_org not set\n"); - return 1; - } - g_strncpy(g_temp_base, g_temp_base_org, 127); - if (mkdtemp(g_temp_base) == 0) - { - printf("g_mk_temp_dir: mkdtemp failed [%s]\n", g_temp_base); - } - } - return 0; + + return 0; } /*****************************************************************************/ void APP_CC -g_init(const char* app_name) +g_init(const char *app_name) { #if defined(_WIN32) - WSADATA wsadata; + WSADATA wsadata; - WSAStartup(2, &wsadata); + WSAStartup(2, &wsadata); #endif - setlocale(LC_CTYPE, ""); - g_mk_temp_dir(app_name); + setlocale(LC_CTYPE, ""); + g_mk_temp_dir(app_name); } /*****************************************************************************/ @@ -168,160 +172,168 @@ void APP_CC g_deinit(void) { #if defined(_WIN32) - WSACleanup(); + WSACleanup(); #endif - g_rm_temp_dir(); + g_rm_temp_dir(); } /*****************************************************************************/ /* allocate memory, returns a pointer to it, size bytes are allocated, if zero is non zero, each byte will be set to zero */ -void* APP_CC +void *APP_CC g_malloc(int size, int zero) { - char* rv; + char *rv; - rv = (char*)malloc(size); - if (zero) - { - if (rv != 0) + rv = (char *)malloc(size); + + if (zero) { - memset(rv, 0, size); + if (rv != 0) + { + memset(rv, 0, size); + } } - } - return rv; + + return rv; } /*****************************************************************************/ /* free the memory pointed to by ptr, ptr can be zero */ void APP_CC -g_free(void* ptr) +g_free(void *ptr) { - if (ptr != 0) - { - free(ptr); - } + if (ptr != 0) + { + free(ptr); + } } /*****************************************************************************/ /* output text to stdout, try to use g_write / g_writeln instead to avoid linux / windows EOL problems */ void DEFAULT_CC -g_printf(const char* format, ...) +g_printf(const char *format, ...) { - va_list ap; + va_list ap; - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); } /*****************************************************************************/ void DEFAULT_CC -g_sprintf(char* dest, const char* format, ...) +g_sprintf(char *dest, const char *format, ...) { - va_list ap; + va_list ap; - va_start(ap, format); - vsprintf(dest, format, ap); - va_end(ap); + va_start(ap, format); + vsprintf(dest, format, ap); + va_end(ap); } /*****************************************************************************/ void DEFAULT_CC -g_snprintf(char* dest, int len, const char* format, ...) +g_snprintf(char *dest, int len, const char *format, ...) { - va_list ap; + va_list ap; - va_start(ap, format); - vsnprintf(dest, len, format, ap); - va_end(ap); + va_start(ap, format); + vsnprintf(dest, len, format, ap); + va_end(ap); } /*****************************************************************************/ void DEFAULT_CC -g_writeln(const char* format, ...) +g_writeln(const char *format, ...) { - va_list ap; + va_list ap; - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); #if defined(_WIN32) - g_printf("\r\n"); + g_printf("\r\n"); #else - g_printf("\n"); + g_printf("\n"); #endif } /*****************************************************************************/ void DEFAULT_CC -g_write(const char* format, ...) +g_write(const char *format, ...) { - va_list ap; + va_list ap; - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); } /*****************************************************************************/ /* produce a hex dump */ void APP_CC -g_hexdump(char* p, int len) +g_hexdump(char *p, int len) { - unsigned char* line; - int i; - int thisline; - int offset; + unsigned char *line; + int i; + int thisline; + int offset; - line = (unsigned char*)p; - offset = 0; - while (offset < len) - { - g_printf("%04x ", offset); - thisline = len - offset; - if (thisline > 16) + line = (unsigned char *)p; + offset = 0; + + while (offset < len) { - thisline = 16; + g_printf("%04x ", offset); + thisline = len - offset; + + if (thisline > 16) + { + thisline = 16; + } + + for (i = 0; i < thisline; i++) + { + g_printf("%02x ", line[i]); + } + + for (; i < 16; i++) + { + g_printf(" "); + } + + for (i = 0; i < thisline; i++) + { + g_printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); + } + + g_writeln(""); + offset += thisline; + line += thisline; } - for (i = 0; i < thisline; i++) - { - g_printf("%02x ", line[i]); - } - for (; i < 16; i++) - { - g_printf(" "); - } - for (i = 0; i < thisline; i++) - { - g_printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); - } - g_writeln(""); - offset += thisline; - line += thisline; - } } /*****************************************************************************/ void APP_CC -g_memset(void* ptr, int val, int size) +g_memset(void *ptr, int val, int size) { - memset(ptr, val, size); + memset(ptr, val, size); } /*****************************************************************************/ void APP_CC -g_memcpy(void* d_ptr, const void* s_ptr, int size) +g_memcpy(void *d_ptr, const void *s_ptr, int size) { - memcpy(d_ptr, s_ptr, size); + memcpy(d_ptr, s_ptr, size); } /*****************************************************************************/ int APP_CC g_getchar(void) { - return getchar(); + return getchar(); } /*****************************************************************************/ @@ -329,40 +341,43 @@ g_getchar(void) int APP_CC g_tcp_set_no_delay(int sck) { - int ret = 1; /* error */ + int ret = 1; /* error */ #if defined(_WIN32) - int option_value; - int option_len; + int option_value; + int option_len; #else - int option_value; - unsigned int option_len; + int option_value; + unsigned int option_len; #endif - option_len = sizeof(option_value); - /* SOL_TCP IPPROTO_TCP */ - if (getsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&option_value, - &option_len) == 0) - { - if (option_value == 0) + option_len = sizeof(option_value); + + /* SOL_TCP IPPROTO_TCP */ + if (getsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char *)&option_value, + &option_len) == 0) { - option_value = 1; - option_len = sizeof(option_value); - if (setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&option_value, - option_len) == 0) - { - ret = 0; /* success */ - } - else - { - g_writeln("Error setting tcp_nodelay"); - } + if (option_value == 0) + { + option_value = 1; + option_len = sizeof(option_value); + + if (setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char *)&option_value, + option_len) == 0) + { + ret = 0; /* success */ + } + else + { + g_writeln("Error setting tcp_nodelay"); + } + } } - } - else - { - g_writeln("Error getting tcp_nodelay"); - } - return ret; + else + { + g_writeln("Error getting tcp_nodelay"); + } + + return ret; } /*****************************************************************************/ @@ -370,40 +385,43 @@ g_tcp_set_no_delay(int sck) int APP_CC g_tcp_set_keepalive(int sck) { - int ret = 1; /* error */ + int ret = 1; /* error */ #if defined(_WIN32) - int option_value; - int option_len; + int option_value; + int option_len; #else - int option_value; - unsigned int option_len; + int option_value; + unsigned int option_len; #endif - option_len = sizeof(option_value); - /* SOL_TCP IPPROTO_TCP */ - if (getsockopt(sck, SOL_SOCKET, SO_KEEPALIVE, (char*)&option_value, - &option_len) == 0) - { - if (option_value == 0) + option_len = sizeof(option_value); + + /* SOL_TCP IPPROTO_TCP */ + if (getsockopt(sck, SOL_SOCKET, SO_KEEPALIVE, (char *)&option_value, + &option_len) == 0) { - option_value = 1; - option_len = sizeof(option_value); - if (setsockopt(sck, SOL_SOCKET, SO_KEEPALIVE, (char*)&option_value, - option_len) == 0) - { - ret = 0; /* success */ - } - else - { - g_writeln("Error setting tcp_keepalive"); - } + if (option_value == 0) + { + option_value = 1; + option_len = sizeof(option_value); + + if (setsockopt(sck, SOL_SOCKET, SO_KEEPALIVE, (char *)&option_value, + option_len) == 0) + { + ret = 0; /* success */ + } + else + { + g_writeln("Error setting tcp_keepalive"); + } + } } - } - else - { - g_writeln("Error getting tcp_keepalive"); - } - return ret; + else + { + g_writeln("Error getting tcp_keepalive"); + } + + return ret; } /*****************************************************************************/ @@ -412,46 +430,52 @@ int APP_CC g_tcp_socket(void) { #if defined(_WIN32) - int rv; - int option_value; - int option_len; + int rv; + int option_value; + int option_len; #else - int rv; - int option_value; - unsigned int option_len; + int rv; + int option_value; + unsigned int option_len; #endif - /* in win32 a socket is an unsigned int, in linux, its an int */ - rv = (int)socket(PF_INET, SOCK_STREAM, 0); - if (rv < 0) - { - return -1; - } - option_len = sizeof(option_value); - if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char*)&option_value, - &option_len) == 0) - { - if (option_value == 0) + /* in win32 a socket is an unsigned int, in linux, its an int */ + rv = (int)socket(PF_INET, SOCK_STREAM, 0); + + if (rv < 0) { - option_value = 1; - option_len = sizeof(option_value); - setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char*)&option_value, - option_len); + return -1; } - } - option_len = sizeof(option_value); - if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char*)&option_value, - &option_len) == 0) - { - if (option_value < (1024 * 32)) + + option_len = sizeof(option_value); + + if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value, + &option_len) == 0) { - option_value = 1024 * 32; - option_len = sizeof(option_value); - setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char*)&option_value, - option_len); + if (option_value == 0) + { + option_value = 1; + option_len = sizeof(option_value); + setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value, + option_len); + } } - } - return rv; + + option_len = sizeof(option_value); + + if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *)&option_value, + &option_len) == 0) + { + if (option_value < (1024 * 32)) + { + option_value = 1024 * 32; + option_len = sizeof(option_value); + setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *)&option_value, + option_len); + } + } + + return rv; } /*****************************************************************************/ @@ -459,9 +483,9 @@ int APP_CC g_tcp_local_socket(void) { #if defined(_WIN32) - return 0; + return 0; #else - return socket(PF_LOCAL, SOCK_STREAM, 0); + return socket(PF_LOCAL, SOCK_STREAM, 0); #endif } @@ -469,63 +493,67 @@ g_tcp_local_socket(void) void APP_CC g_tcp_close(int sck) { - if (sck == 0) - { - return; - } + if (sck == 0) + { + return; + } + #if defined(_WIN32) - closesocket(sck); + closesocket(sck); #else - close(sck); + close(sck); #endif } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC -g_tcp_connect(int sck, const char* address, const char* port) +g_tcp_connect(int sck, const char *address, const char *port) { - struct sockaddr_in s; - struct hostent* h; + struct sockaddr_in s; + struct hostent *h; - g_memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons((tui16)atoi(port)); - s.sin_addr.s_addr = inet_addr(address); - if (s.sin_addr.s_addr == INADDR_NONE) - { - h = gethostbyname(address); - if (h != 0) + g_memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons((tui16)atoi(port)); + s.sin_addr.s_addr = inet_addr(address); + + if (s.sin_addr.s_addr == INADDR_NONE) { - if (h->h_name != 0) - { - if (h->h_addr_list != 0) + h = gethostbyname(address); + + if (h != 0) { - if ((*(h->h_addr_list)) != 0) - { - s.sin_addr.s_addr = *((int*)(*(h->h_addr_list))); - } + if (h->h_name != 0) + { + if (h->h_addr_list != 0) + { + if ((*(h->h_addr_list)) != 0) + { + s.sin_addr.s_addr = *((int *)(*(h->h_addr_list))); + } + } + } } - } } - } - return connect(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); + + return connect(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC -g_tcp_local_connect(int sck, const char* port) +g_tcp_local_connect(int sck, const char *port) { #if defined(_WIN32) - return -1; + return -1; #else - struct sockaddr_un s; + struct sockaddr_un s; - memset(&s, 0, sizeof(struct sockaddr_un)); - s.sun_family = AF_UNIX; - strcpy(s.sun_path, port); - return connect(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_un)); + memset(&s, 0, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, port); + return connect(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_un)); #endif } @@ -533,65 +561,67 @@ g_tcp_local_connect(int sck, const char* port) int APP_CC g_tcp_set_non_blocking(int sck) { - unsigned long i; + unsigned long i; #if defined(_WIN32) - i = 1; - ioctlsocket(sck, FIONBIO, &i); + i = 1; + ioctlsocket(sck, FIONBIO, &i); #else - i = fcntl(sck, F_GETFL); - i = i | O_NONBLOCK; - fcntl(sck, F_SETFL, i); + i = fcntl(sck, F_GETFL); + i = i | O_NONBLOCK; + fcntl(sck, F_SETFL, i); #endif - return 0; + return 0; } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC -g_tcp_bind(int sck, char* port) +g_tcp_bind(int sck, char *port) { - struct sockaddr_in s; + struct sockaddr_in s; - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons((tui16)atoi(port)); - s.sin_addr.s_addr = INADDR_ANY; - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons((tui16)atoi(port)); + s.sin_addr.s_addr = INADDR_ANY; + return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); } /*****************************************************************************/ int APP_CC -g_tcp_local_bind(int sck, char* port) +g_tcp_local_bind(int sck, char *port) { #if defined(_WIN32) - return -1; + return -1; #else - struct sockaddr_un s; + struct sockaddr_un s; - memset(&s, 0, sizeof(struct sockaddr_un)); - s.sun_family = AF_UNIX; - strcpy(s.sun_path, port); - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_un)); + memset(&s, 0, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, port); + return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_un)); #endif } /*****************************************************************************/ /* returns error, zero is good */ int APP_CC -g_tcp_bind_address(int sck, char* port, const char* address) +g_tcp_bind_address(int sck, char *port, const char *address) { - struct sockaddr_in s; + struct sockaddr_in s; - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons((tui16)atoi(port)); - s.sin_addr.s_addr = INADDR_ANY; - if (inet_aton(address, &s.sin_addr) < 0) - { - return -1; /* bad address */ - } - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons((tui16)atoi(port)); + s.sin_addr.s_addr = INADDR_ANY; + + if (inet_aton(address, &s.sin_addr) < 0) + { + return -1; /* bad address */ + } + + return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); } /*****************************************************************************/ @@ -599,58 +629,61 @@ g_tcp_bind_address(int sck, char* port, const char* address) int APP_CC g_tcp_listen(int sck) { - return listen(sck, 2); + return listen(sck, 2); } /*****************************************************************************/ int APP_CC g_tcp_accept(int sck) { - struct sockaddr_in s; + struct sockaddr_in s; #if defined(_WIN32) - signed int i; + signed int i; #else - unsigned int i; + unsigned int i; #endif - i = sizeof(struct sockaddr_in); - memset(&s, 0, i); - return accept(sck, (struct sockaddr*)&s, &i); + i = sizeof(struct sockaddr_in); + memset(&s, 0, i); + return accept(sck, (struct sockaddr *)&s, &i); } /*****************************************************************************/ void APP_CC -g_write_ip_address(int rcv_sck, char* ip_address, int bytes) +g_write_ip_address(int rcv_sck, char *ip_address, int bytes) { - struct sockaddr_in s; - struct in_addr in; + struct sockaddr_in s; + struct in_addr in; #if defined(_WIN32) - int len; + int len; #else - unsigned int len; + unsigned int len; #endif - int ip_port; - int ok; + int ip_port; + int ok; - ok = 0; - memset(&s, 0, sizeof(s)); - len = sizeof(s); - if (getpeername(rcv_sck,(struct sockaddr*)&s, &len) == 0) - { - memset(&in, 0, sizeof(in)); - in.s_addr = s.sin_addr.s_addr; - ip_port = ntohs(s.sin_port); - if (ip_port != 0) + ok = 0; + memset(&s, 0, sizeof(s)); + len = sizeof(s); + + if (getpeername(rcv_sck, (struct sockaddr *)&s, &len) == 0) { - ok = 1; - snprintf(ip_address, bytes, "%s:%d - socket: %d", inet_ntoa(in), - ip_port, rcv_sck); + memset(&in, 0, sizeof(in)); + in.s_addr = s.sin_addr.s_addr; + ip_port = ntohs(s.sin_port); + + if (ip_port != 0) + { + ok = 1; + snprintf(ip_address, bytes, "%s:%d - socket: %d", inet_ntoa(in), + ip_port, rcv_sck); + } + } + + if (!ok) + { + snprintf(ip_address, bytes, "NULL:NULL - socket: %d", rcv_sck); } - } - if (!ok) - { - snprintf(ip_address, bytes, "NULL:NULL - socket: %d", rcv_sck); - } } /*****************************************************************************/ @@ -658,9 +691,9 @@ void APP_CC g_sleep(int msecs) { #if defined(_WIN32) - Sleep(msecs); + Sleep(msecs); #else - usleep(msecs * 1000); + usleep(msecs * 1000); #endif } @@ -669,31 +702,31 @@ int APP_CC g_tcp_last_error_would_block(int sck) { #if defined(_WIN32) - return WSAGetLastError() == WSAEWOULDBLOCK; + return WSAGetLastError() == WSAEWOULDBLOCK; #else - return (errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINPROGRESS); + return (errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINPROGRESS); #endif } /*****************************************************************************/ int APP_CC -g_tcp_recv(int sck, void* ptr, int len, int flags) +g_tcp_recv(int sck, void *ptr, int len, int flags) { #if defined(_WIN32) - return recv(sck, (char*)ptr, len, flags); + return recv(sck, (char *)ptr, len, flags); #else - return recv(sck, ptr, len, flags); + return recv(sck, ptr, len, flags); #endif } /*****************************************************************************/ int APP_CC -g_tcp_send(int sck, const void* ptr, int len, int flags) +g_tcp_send(int sck, const void *ptr, int len, int flags) { #if defined(_WIN32) - return send(sck, (const char*)ptr, len, flags); + return send(sck, (const char *)ptr, len, flags); #else - return send(sck, ptr, len, flags); + return send(sck, ptr, len, flags); #endif } @@ -703,22 +736,24 @@ int APP_CC g_tcp_socket_ok(int sck) { #if defined(_WIN32) - int opt; - int opt_len; + int opt; + int opt_len; #else - int opt; - unsigned int opt_len; + int opt; + unsigned int opt_len; #endif - opt_len = sizeof(opt); - if (getsockopt(sck, SOL_SOCKET, SO_ERROR, (char*)(&opt), &opt_len) == 0) - { - if (opt == 0) + opt_len = sizeof(opt); + + if (getsockopt(sck, SOL_SOCKET, SO_ERROR, (char *)(&opt), &opt_len) == 0) { - return 1; + if (opt == 0) + { + return 1; + } } - } - return 0; + + return 0; } /*****************************************************************************/ @@ -727,23 +762,26 @@ g_tcp_socket_ok(int sck) int APP_CC g_tcp_can_send(int sck, int millis) { - fd_set wfds; - struct timeval time; - int rv; + fd_set wfds; + struct timeval time; + int rv; - time.tv_sec = millis / 1000; - time.tv_usec = (millis * 1000) % 1000000; - FD_ZERO(&wfds); - if (sck > 0) - { - FD_SET(((unsigned int)sck), &wfds); - rv = select(sck + 1, 0, &wfds, 0, &time); - if (rv > 0) + time.tv_sec = millis / 1000; + time.tv_usec = (millis * 1000) % 1000000; + FD_ZERO(&wfds); + + if (sck > 0) { - return g_tcp_socket_ok(sck); + FD_SET(((unsigned int)sck), &wfds); + rv = select(sck + 1, 0, &wfds, 0, &time); + + if (rv > 0) + { + return g_tcp_socket_ok(sck); + } } - } - return 0; + + return 0; } /*****************************************************************************/ @@ -752,144 +790,166 @@ g_tcp_can_send(int sck, int millis) int APP_CC g_tcp_can_recv(int sck, int millis) { - fd_set rfds; - struct timeval time; - int rv; + fd_set rfds; + struct timeval time; + int rv; - time.tv_sec = millis / 1000; - time.tv_usec = (millis * 1000) % 1000000; - FD_ZERO(&rfds); - if (sck > 0) - { - FD_SET(((unsigned int)sck), &rfds); - rv = select(sck + 1, &rfds, 0, 0, &time); - if (rv > 0) + time.tv_sec = millis / 1000; + time.tv_usec = (millis * 1000) % 1000000; + FD_ZERO(&rfds); + + if (sck > 0) { - return g_tcp_socket_ok(sck); + FD_SET(((unsigned int)sck), &rfds); + rv = select(sck + 1, &rfds, 0, 0, &time); + + if (rv > 0) + { + return g_tcp_socket_ok(sck); + } } - } - return 0; + + return 0; } /*****************************************************************************/ int APP_CC g_tcp_select(int sck1, int sck2) { - fd_set rfds; - struct timeval time; - int max = 0; - int rv = 0; + fd_set rfds; + struct timeval time; + int max = 0; + int rv = 0; - g_memset(&rfds,0,sizeof(fd_set)); - g_memset(&time,0,sizeof(struct timeval)); + g_memset(&rfds, 0, sizeof(fd_set)); + g_memset(&time, 0, sizeof(struct timeval)); - time.tv_sec = 0; - time.tv_usec = 0; - FD_ZERO(&rfds); - if (sck1 > 0) - { - FD_SET(((unsigned int)sck1), &rfds); - } - if (sck2 > 0) - { - FD_SET(((unsigned int)sck2), &rfds); - } - max = sck1; - if (sck2 > max) - { - max = sck2; - } - rv = select(max + 1, &rfds, 0, 0, &time); - if (rv > 0) - { - rv = 0; - if (FD_ISSET(((unsigned int)sck1), &rfds)) + time.tv_sec = 0; + time.tv_usec = 0; + FD_ZERO(&rfds); + + if (sck1 > 0) { - rv = rv | 1; + FD_SET(((unsigned int)sck1), &rfds); } - if (FD_ISSET(((unsigned int)sck2), &rfds)) + + if (sck2 > 0) { - rv = rv | 2; + FD_SET(((unsigned int)sck2), &rfds); } - } - else - { - rv = 0; - } - return rv; + + max = sck1; + + if (sck2 > max) + { + max = sck2; + } + + rv = select(max + 1, &rfds, 0, 0, &time); + + if (rv > 0) + { + rv = 0; + + if (FD_ISSET(((unsigned int)sck1), &rfds)) + { + rv = rv | 1; + } + + if (FD_ISSET(((unsigned int)sck2), &rfds)) + { + rv = rv | 2; + } + } + else + { + rv = 0; + } + + return rv; } /*****************************************************************************/ /* returns 0 on error */ tbus APP_CC -g_create_wait_obj(char* name) +g_create_wait_obj(char *name) { #ifdef _WIN32 - tbus obj; + tbus obj; - obj = (tbus)CreateEvent(0, 1, 0, name); - return obj; + obj = (tbus)CreateEvent(0, 1, 0, name); + return obj; #else - tbus obj; - struct sockaddr_un sa; - size_t len; - tbus sck; - int i; - int safety; - int unnamed; + tbus obj; + struct sockaddr_un sa; + size_t len; + tbus sck; + int i; + int safety; + int unnamed; - if (g_temp_base[0] == 0) - { - return 0; - } - sck = socket(PF_UNIX, SOCK_DGRAM, 0); - if (sck < 0) - { - return 0; - } - safety = 0; - g_memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_UNIX; - unnamed = 1; - if (name != 0) - { - if (name[0] != 0) + if (g_temp_base[0] == 0) { - unnamed = 0; + return 0; } - } - if (unnamed) - { - do + + sck = socket(PF_UNIX, SOCK_DGRAM, 0); + + if (sck < 0) { - if (safety > 100) - { - break; - } - safety++; - g_random((char*)&i, sizeof(i)); - len = sizeof(sa.sun_path); - g_snprintf(sa.sun_path, len, "%s/auto_%8.8x", g_temp_base, i); - len = sizeof(sa); - } while (bind(sck, (struct sockaddr*)&sa, len) < 0); - } - else - { - do + return 0; + } + + safety = 0; + g_memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + unnamed = 1; + + if (name != 0) { - if (safety > 100) - { - break; - } - safety++; - g_random((char*)&i, sizeof(i)); - len = sizeof(sa.sun_path); - g_snprintf(sa.sun_path, len, "%s/%s_%8.8x", g_temp_base, name, i); - len = sizeof(sa); - } while (bind(sck, (struct sockaddr*)&sa, len) < 0); - } - obj = (tbus)sck; - return obj; + if (name[0] != 0) + { + unnamed = 0; + } + } + + if (unnamed) + { + do + { + if (safety > 100) + { + break; + } + + safety++; + g_random((char *)&i, sizeof(i)); + len = sizeof(sa.sun_path); + g_snprintf(sa.sun_path, len, "%s/auto_%8.8x", g_temp_base, i); + len = sizeof(sa); + } + while (bind(sck, (struct sockaddr *)&sa, len) < 0); + } + else + { + do + { + if (safety > 100) + { + break; + } + + safety++; + g_random((char *)&i, sizeof(i)); + len = sizeof(sa.sun_path); + g_snprintf(sa.sun_path, len, "%s/%s_%8.8x", g_temp_base, name, i); + len = sizeof(sa); + } + while (bind(sck, (struct sockaddr *)&sa, len) < 0); + } + + obj = (tbus)sck; + return obj; #endif } @@ -899,24 +959,26 @@ tbus APP_CC g_create_wait_obj_from_socket(tbus socket, int write) { #ifdef _WIN32 - /* Create and return corresponding event handle for WaitForMultipleObjets */ - WSAEVENT event; - long lnetevent = 0; + /* Create and return corresponding event handle for WaitForMultipleObjets */ + WSAEVENT event; + long lnetevent = 0; - g_memset(&event,0,sizeof(WSAEVENT)); + g_memset(&event, 0, sizeof(WSAEVENT)); + + event = WSACreateEvent(); + lnetevent = (write ? FD_WRITE : FD_READ) | FD_CLOSE; + + if (WSAEventSelect(socket, event, lnetevent) == 0) + { + return (tbus)event; + } + else + { + return 0; + } - event = WSACreateEvent(); - lnetevent = (write ? FD_WRITE : FD_READ) | FD_CLOSE; - if (WSAEventSelect(socket, event, lnetevent) == 0) - { - return (tbus)event; - } - else - { - return 0; - } #else - return socket; + return socket; #endif } @@ -925,11 +987,13 @@ void APP_CC g_delete_wait_obj_from_socket(tbus wait_obj) { #ifdef _WIN32 - if (wait_obj == 0) - { - return; - } - WSACloseEvent((HANDLE)wait_obj); + + if (wait_obj == 0) + { + return; + } + + WSACloseEvent((HANDLE)wait_obj); #else #endif } @@ -940,39 +1004,47 @@ int APP_CC g_set_wait_obj(tbus obj) { #ifdef _WIN32 - if (obj == 0) - { - return 0; - } - SetEvent((HANDLE)obj); - return 0; -#else - socklen_t sa_size; - int s; - struct sockaddr_un sa; - if (obj == 0) - { + if (obj == 0) + { + return 0; + } + + SetEvent((HANDLE)obj); return 0; - } - if (g_tcp_can_recv((int)obj, 0)) - { - /* already signalled */ +#else + socklen_t sa_size; + int s; + struct sockaddr_un sa; + + if (obj == 0) + { + return 0; + } + + if (g_tcp_can_recv((int)obj, 0)) + { + /* already signalled */ + return 0; + } + + sa_size = sizeof(sa); + + if (getsockname((int)obj, (struct sockaddr *)&sa, &sa_size) < 0) + { + return 1; + } + + s = socket(PF_UNIX, SOCK_DGRAM, 0); + + if (s < 0) + { + return 1; + } + + sendto(s, "sig", 4, 0, (struct sockaddr *)&sa, sa_size); + close(s); return 0; - } - sa_size = sizeof(sa); - if (getsockname((int)obj, (struct sockaddr*)&sa, &sa_size) < 0) - { - return 1; - } - s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (s < 0) - { - return 1; - } - sendto(s, "sig", 4, 0, (struct sockaddr*)&sa, sa_size); - close(s); - return 0; #endif } @@ -982,24 +1054,28 @@ int APP_CC g_reset_wait_obj(tbus obj) { #ifdef _WIN32 - if (obj == 0) - { - return 0; - } - ResetEvent((HANDLE)obj); - return 0; -#else - char buf[64]; - if (obj == 0) - { + if (obj == 0) + { + return 0; + } + + ResetEvent((HANDLE)obj); + return 0; +#else + char buf[64]; + + if (obj == 0) + { + return 0; + } + + while (g_tcp_can_recv((int)obj, 0)) + { + recvfrom((int)obj, &buf, 64, 0, 0, 0); + } + return 0; - } - while (g_tcp_can_recv((int)obj, 0)) - { - recvfrom((int)obj, &buf, 64, 0, 0, 0); - } - return 0; #endif } @@ -1009,21 +1085,26 @@ int APP_CC g_is_wait_obj_set(tbus obj) { #ifdef _WIN32 - if (obj == 0) - { + + if (obj == 0) + { + return 0; + } + + if (WaitForSingleObject((HANDLE)obj, 0) == WAIT_OBJECT_0) + { + return 1; + } + return 0; - } - if (WaitForSingleObject((HANDLE)obj, 0) == WAIT_OBJECT_0) - { - return 1; - } - return 0; #else - if (obj == 0) - { - return 0; - } - return g_tcp_can_recv((int)obj, 0); + + if (obj == 0) + { + return 0; + } + + return g_tcp_can_recv((int)obj, 0); #endif } @@ -1033,29 +1114,34 @@ int APP_CC g_delete_wait_obj(tbus obj) { #ifdef _WIN32 - if (obj == 0) - { - return 0; - } - /* Close event handle */ - CloseHandle((HANDLE)obj); - return 0; -#else - socklen_t sa_size; - struct sockaddr_un sa; - if (obj == 0) - { + if (obj == 0) + { + return 0; + } + + /* Close event handle */ + CloseHandle((HANDLE)obj); + return 0; +#else + socklen_t sa_size; + struct sockaddr_un sa; + + if (obj == 0) + { + return 0; + } + + sa_size = sizeof(sa); + + if (getsockname((int)obj, (struct sockaddr *)&sa, &sa_size) < 0) + { + return 1; + } + + close((int)obj); + unlink(sa.sun_path); return 0; - } - sa_size = sizeof(sa); - if (getsockname((int)obj, (struct sockaddr*)&sa, &sa_size) < 0) - { - return 1; - } - close((int)obj); - unlink(sa.sun_path); - return 0; #endif } @@ -1067,158 +1153,182 @@ g_close_wait_obj(tbus obj) { #ifdef _WIN32 #else - close((int)obj); + close((int)obj); #endif - return 0; + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -g_obj_wait(tbus* read_objs, int rcount, tbus* write_objs, int wcount, +g_obj_wait(tbus *read_objs, int rcount, tbus *write_objs, int wcount, int mstimeout) { #ifdef _WIN32 - HANDLE handles[256]; - DWORD count; - DWORD error; - int j; - int i; + HANDLE handles[256]; + DWORD count; + DWORD error; + int j; + int i; - j = 0; - count = rcount + wcount; - for (i = 0; i < rcount; i++) - { - handles[j++] = (HANDLE)(read_objs[i]); - } - for (i = 0; i < wcount; i++) - { - handles[j++] = (HANDLE)(write_objs[i]); - } - if (mstimeout < 1) - { - mstimeout = INFINITE; - } - error = WaitForMultipleObjects(count, handles, FALSE, mstimeout); - if (error == WAIT_FAILED) - { - return 1; - } - return 0; -#else - fd_set rfds; - fd_set wfds; - struct timeval time; - struct timeval* ptime = (struct timeval *)NULL; - int i = 0; - int res = 0; - int max = 0; - int sck = 0; + j = 0; + count = rcount + wcount; - g_memset(&rfds,0,sizeof(fd_set)); - g_memset(&wfds,0,sizeof(fd_set)); - g_memset(&time,0,sizeof(struct timeval)); - - max = 0; - if (mstimeout < 1) - { - ptime = (struct timeval *)NULL; - } - else - { - time.tv_sec = mstimeout / 1000; - time.tv_usec = (mstimeout % 1000) * 1000; - ptime = &time; - } - FD_ZERO(&rfds); - FD_ZERO(&wfds); - /* Find the highest descriptor number in read_obj */ - if (read_objs!=NULL) - { for (i = 0; i < rcount; i++) { - sck = (int)(read_objs[i]); - if (sck > 0) - { - FD_SET(sck, &rfds); - if (sck > max) - { - max = sck; /* max holds the highest socket/descriptor number */ - } - } + handles[j++] = (HANDLE)(read_objs[i]); } - } - else if (rcount>0) - { - g_writeln("Programming error read_objs is null"); - return 1; /* error */ - } - if (write_objs!=NULL) - { + for (i = 0; i < wcount; i++) { - sck = (int)(write_objs[i]); - if (sck > 0) - { - FD_SET(sck, &wfds); - if (sck > max) - { - max = sck; /* max holds the highest socket/descriptor number */ - } - } + handles[j++] = (HANDLE)(write_objs[i]); } - } - else if (wcount > 0) - { - g_writeln("Programming error write_objs is null"); - return 1; /* error */ - } - res = select(max + 1, &rfds, &wfds, 0, ptime); - if (res < 0) - { - /* these are not really errors */ - if ((errno == EAGAIN) || - (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || - (errno == EINTR)) /* signal occurred */ + + if (mstimeout < 1) { - return 0; + mstimeout = INFINITE; } - return 1; /* error */ - } - return 0; + + error = WaitForMultipleObjects(count, handles, FALSE, mstimeout); + + if (error == WAIT_FAILED) + { + return 1; + } + + return 0; +#else + fd_set rfds; + fd_set wfds; + struct timeval time; + struct timeval *ptime = (struct timeval *)NULL; + int i = 0; + int res = 0; + int max = 0; + int sck = 0; + + g_memset(&rfds, 0, sizeof(fd_set)); + g_memset(&wfds, 0, sizeof(fd_set)); + g_memset(&time, 0, sizeof(struct timeval)); + + max = 0; + + if (mstimeout < 1) + { + ptime = (struct timeval *)NULL; + } + else + { + time.tv_sec = mstimeout / 1000; + time.tv_usec = (mstimeout % 1000) * 1000; + ptime = &time; + } + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + /* Find the highest descriptor number in read_obj */ + if (read_objs != NULL) + { + for (i = 0; i < rcount; i++) + { + sck = (int)(read_objs[i]); + + if (sck > 0) + { + FD_SET(sck, &rfds); + + if (sck > max) + { + max = sck; /* max holds the highest socket/descriptor number */ + } + } + } + } + else if (rcount > 0) + { + g_writeln("Programming error read_objs is null"); + return 1; /* error */ + } + + if (write_objs != NULL) + { + for (i = 0; i < wcount; i++) + { + sck = (int)(write_objs[i]); + + if (sck > 0) + { + FD_SET(sck, &wfds); + + if (sck > max) + { + max = sck; /* max holds the highest socket/descriptor number */ + } + } + } + } + else if (wcount > 0) + { + g_writeln("Programming error write_objs is null"); + return 1; /* error */ + } + + res = select(max + 1, &rfds, &wfds, 0, ptime); + + if (res < 0) + { + /* these are not really errors */ + if ((errno == EAGAIN) || + (errno == EWOULDBLOCK) || + (errno == EINPROGRESS) || + (errno == EINTR)) /* signal occurred */ + { + return 0; + } + + return 1; /* error */ + } + + return 0; #endif } /*****************************************************************************/ void APP_CC -g_random(char* data, int len) +g_random(char *data, int len) { #if defined(_WIN32) - int index; + int index; - srand(g_time1()); - for (index = 0; index < len; index++) - { - data[index] = (char)rand(); /* rand returns a number between 0 and - RAND_MAX */ - } -#else - int fd; + srand(g_time1()); - memset(data, 0x44, len); - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) - { - fd = open("/dev/random", O_RDONLY); - } - if (fd != -1) - { - if (read(fd, data, len) != len) + for (index = 0; index < len; index++) { + data[index] = (char)rand(); /* rand returns a number between 0 and + RAND_MAX */ } - close(fd); - } + +#else + int fd; + + memset(data, 0x44, len); + fd = open("/dev/urandom", O_RDONLY); + + if (fd == -1) + { + fd = open("/dev/random", O_RDONLY); + } + + if (fd != -1) + { + if (read(fd, data, len) != len) + { + } + + close(fd); + } + #endif } @@ -1226,35 +1336,37 @@ g_random(char* data, int len) int APP_CC g_abs(int i) { - return abs(i); + return abs(i); } /*****************************************************************************/ int APP_CC -g_memcmp(const void* s1, const void* s2, int len) +g_memcmp(const void *s1, const void *s2, int len) { - return memcmp(s1, s2, len); + return memcmp(s1, s2, len); } /*****************************************************************************/ /* returns -1 on error, else return handle or file descriptor */ int APP_CC -g_file_open(const char* file_name) +g_file_open(const char *file_name) { #if defined(_WIN32) - return (int)CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + return (int)CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); #else - int rv; + int rv; - rv = open(file_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - if (rv == -1) - { - /* can't open read / write, try to open read only */ - rv = open(file_name, O_RDONLY); - } - return rv; + rv = open(file_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + + if (rv == -1) + { + /* can't open read / write, try to open read only */ + rv = open(file_name, O_RDONLY); + } + + return rv; #endif } @@ -1264,48 +1376,52 @@ int APP_CC g_file_close(int fd) { #if defined(_WIN32) - CloseHandle((HANDLE)fd); + CloseHandle((HANDLE)fd); #else - close(fd); + close(fd); #endif - return 0; + return 0; } /*****************************************************************************/ /* read from file, returns the number of bytes read or -1 on error */ int APP_CC -g_file_read(int fd, char* ptr, int len) +g_file_read(int fd, char *ptr, int len) { #if defined(_WIN32) - if (ReadFile((HANDLE)fd, (LPVOID)ptr, (DWORD)len, (LPDWORD)&len, 0)) - { - return len; - } - else - { - return -1; - } + + if (ReadFile((HANDLE)fd, (LPVOID)ptr, (DWORD)len, (LPDWORD)&len, 0)) + { + return len; + } + else + { + return -1; + } + #else - return read(fd, ptr, len); + return read(fd, ptr, len); #endif } /*****************************************************************************/ /* write to file, returns the number of bytes writen or -1 on error */ int APP_CC -g_file_write(int fd, char* ptr, int len) +g_file_write(int fd, char *ptr, int len) { #if defined(_WIN32) - if (WriteFile((HANDLE)fd, (LPVOID)ptr, (DWORD)len, (LPDWORD)&len, 0)) - { - return len; - } - else - { - return -1; - } + + if (WriteFile((HANDLE)fd, (LPVOID)ptr, (DWORD)len, (LPDWORD)&len, 0)) + { + return len; + } + else + { + return -1; + } + #else - return write(fd, ptr, len); + return write(fd, ptr, len); #endif } @@ -1315,19 +1431,21 @@ int APP_CC g_file_seek(int fd, int offset) { #if defined(_WIN32) - int rv; + int rv; + + rv = (int)SetFilePointer((HANDLE)fd, offset, 0, FILE_BEGIN); + + if (rv == (int)INVALID_SET_FILE_POINTER) + { + return -1; + } + else + { + return rv; + } - rv = (int)SetFilePointer((HANDLE)fd, offset, 0, FILE_BEGIN); - if (rv == (int)INVALID_SET_FILE_POINTER) - { - return -1; - } - else - { - return rv; - } #else - return (int)lseek(fd, offset, SEEK_SET); + return (int)lseek(fd, offset, SEEK_SET); #endif } @@ -1338,67 +1456,69 @@ int APP_CC g_file_lock(int fd, int start, int len) { #if defined(_WIN32) - return LockFile((HANDLE)fd, start, 0, len, 0); + return LockFile((HANDLE)fd, start, 0, len, 0); #else - struct flock lock; + 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 0; - } - return 1; + 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 0; + } + + return 1; #endif } /*****************************************************************************/ /* returns error */ int APP_CC -g_chmod_hex(const char* filename, int flags) +g_chmod_hex(const char *filename, int flags) { #if defined(_WIN32) - return 0; + return 0; #else - int fl; + int fl; - fl = 0; - fl |= (flags & 0x4000) ? S_ISUID : 0; - fl |= (flags & 0x2000) ? S_ISGID : 0; - fl |= (flags & 0x1000) ? S_ISVTX : 0; - fl |= (flags & 0x0400) ? S_IRUSR : 0; - fl |= (flags & 0x0200) ? S_IWUSR : 0; - fl |= (flags & 0x0100) ? S_IXUSR : 0; - fl |= (flags & 0x0040) ? S_IRGRP : 0; - fl |= (flags & 0x0020) ? S_IWGRP : 0; - fl |= (flags & 0x0010) ? S_IXGRP : 0; - fl |= (flags & 0x0004) ? S_IROTH : 0; - fl |= (flags & 0x0002) ? S_IWOTH : 0; - fl |= (flags & 0x0001) ? S_IXOTH : 0; - return chmod(filename, fl); + fl = 0; + fl |= (flags & 0x4000) ? S_ISUID : 0; + fl |= (flags & 0x2000) ? S_ISGID : 0; + fl |= (flags & 0x1000) ? S_ISVTX : 0; + fl |= (flags & 0x0400) ? S_IRUSR : 0; + fl |= (flags & 0x0200) ? S_IWUSR : 0; + fl |= (flags & 0x0100) ? S_IXUSR : 0; + fl |= (flags & 0x0040) ? S_IRGRP : 0; + fl |= (flags & 0x0020) ? S_IWGRP : 0; + fl |= (flags & 0x0010) ? S_IXGRP : 0; + fl |= (flags & 0x0004) ? S_IROTH : 0; + fl |= (flags & 0x0002) ? S_IWOTH : 0; + fl |= (flags & 0x0001) ? S_IXOTH : 0; + return chmod(filename, fl); #endif } /*****************************************************************************/ /* returns error, zero is ok */ int APP_CC -g_chown(const char* name, int uid, int gid) +g_chown(const char *name, int uid, int gid) { - return chown(name, uid, gid); + return chown(name, uid, gid); } /*****************************************************************************/ /* returns error, always zero */ int APP_CC -g_mkdir(const char* dirname) +g_mkdir(const char *dirname) { #if defined(_WIN32) - return 0; + return 0; #else - mkdir(dirname, S_IRWXU); - return 0; + mkdir(dirname, S_IRWXU); + return 0; #endif } @@ -1406,82 +1526,87 @@ g_mkdir(const char* dirname) /* gets the current working directory and puts up to maxlen chars in dirname always returns 0 */ -char* APP_CC -g_get_current_dir(char* dirname, int maxlen) +char *APP_CC +g_get_current_dir(char *dirname, int maxlen) { #if defined(_WIN32) - GetCurrentDirectoryA(maxlen, dirname); - return 0; + GetCurrentDirectoryA(maxlen, dirname); + return 0; #else - if (getcwd(dirname, maxlen) == 0) - { - } - return 0; + + if (getcwd(dirname, maxlen) == 0) + { + } + + return 0; #endif } /*****************************************************************************/ /* returns error, zero on success and -1 on failure */ int APP_CC -g_set_current_dir(char* dirname) +g_set_current_dir(char *dirname) { #if defined(_WIN32) - if (SetCurrentDirectoryA(dirname)) - { - return 0; - } - else - { - return -1; - } + + if (SetCurrentDirectoryA(dirname)) + { + return 0; + } + else + { + return -1; + } + #else - return chdir(dirname); + return chdir(dirname); #endif } /*****************************************************************************/ /* returns boolean, non zero if the file exists */ int APP_CC -g_file_exist(const char* filename) +g_file_exist(const char *filename) { #if defined(_WIN32) - return 0; // use FileAge(filename) <> -1 + return 0; // use FileAge(filename) <> -1 #else - return access(filename, F_OK) == 0; + return access(filename, F_OK) == 0; #endif } /*****************************************************************************/ /* returns boolean, non zero if the directory exists */ int APP_CC -g_directory_exist(const char* dirname) +g_directory_exist(const char *dirname) { #if defined(_WIN32) - return 0; // use GetFileAttributes and check return value - // is not -1 and FILE_ATTRIBUT_DIRECTORY bit is set + return 0; // use GetFileAttributes and check return value + // is not -1 and FILE_ATTRIBUT_DIRECTORY bit is set #else - struct stat st; + struct stat st; + + if (stat(dirname, &st) == 0) + { + return S_ISDIR(st.st_mode); + } + else + { + return 0; + } - if (stat(dirname, &st) == 0) - { - return S_ISDIR(st.st_mode); - } - else - { - return 0; - } #endif } /*****************************************************************************/ /* returns boolean */ int APP_CC -g_create_dir(const char* dirname) +g_create_dir(const char *dirname) { #if defined(_WIN32) - return CreateDirectoryA(dirname, 0); // test this + return CreateDirectoryA(dirname, 0); // test this #else - return mkdir(dirname, (mode_t)-1) == 0; + return mkdir(dirname, (mode_t) - 1) == 0; #endif } @@ -1490,353 +1615,380 @@ g_create_dir(const char* dirname) example /tmp/a/b/c/readme.txt will try to create /tmp/a/b/c returns boolean */ int APP_CC -g_create_path(const char* path) +g_create_path(const char *path) { - char* pp; - char* sp; - char* copypath; - int status; + char *pp; + char *sp; + char *copypath; + int status; - status = 1; - copypath = g_strdup(path); - pp = copypath; - sp = strchr(pp, '/'); - while (sp != 0) - { - if (sp != pp) - { - *sp = 0; - if (!g_directory_exist(copypath)) - { - if (!g_create_dir(copypath)) - { - status = 0; - break; - } - } - *sp = '/'; - } - pp = sp + 1; + status = 1; + copypath = g_strdup(path); + pp = copypath; sp = strchr(pp, '/'); - } - g_free(copypath); - return status; + + while (sp != 0) + { + if (sp != pp) + { + *sp = 0; + + if (!g_directory_exist(copypath)) + { + if (!g_create_dir(copypath)) + { + status = 0; + break; + } + } + + *sp = '/'; + } + + pp = sp + 1; + sp = strchr(pp, '/'); + } + + g_free(copypath); + return status; } /*****************************************************************************/ /* returns boolean */ int APP_CC -g_remove_dir(const char* dirname) +g_remove_dir(const char *dirname) { #if defined(_WIN32) - return RemoveDirectoryA(dirname); // test this + return RemoveDirectoryA(dirname); // test this #else - return rmdir(dirname) == 0; + return rmdir(dirname) == 0; #endif } /*****************************************************************************/ /* returns non zero if the file was deleted */ int APP_CC -g_file_delete(const char* filename) +g_file_delete(const char *filename) { #if defined(_WIN32) - return DeleteFileA(filename); + return DeleteFileA(filename); #else - return unlink(filename) != -1; + return unlink(filename) != -1; #endif } /*****************************************************************************/ /* returns file size, -1 on error */ int APP_CC -g_file_get_size(const char* filename) +g_file_get_size(const char *filename) { #if defined(_WIN32) - return -1; -#else - struct stat st; - - if (stat(filename, &st) == 0) - { - return (int)(st.st_size); - } - else - { return -1; - } +#else + struct stat st; + + if (stat(filename, &st) == 0) + { + return (int)(st.st_size); + } + else + { + return -1; + } + #endif } /*****************************************************************************/ /* returns length of text */ int APP_CC -g_strlen(const char* text) +g_strlen(const char *text) { - if (text == NULL) - { - return 0; - } - return strlen(text); + if (text == NULL) + { + return 0; + } + + return strlen(text); } /*****************************************************************************/ /* returns dest */ -char* APP_CC -g_strcpy(char* dest, const char* src) +char *APP_CC +g_strcpy(char *dest, const char *src) { - if (src == 0 && dest != 0) - { - dest[0] = 0; - return dest; - } - if (dest == 0 || src == 0) - { - return 0; - } - return strcpy(dest, src); + if (src == 0 && dest != 0) + { + dest[0] = 0; + return dest; + } + + if (dest == 0 || src == 0) + { + return 0; + } + + return strcpy(dest, src); } /*****************************************************************************/ /* returns dest */ -char* APP_CC -g_strncpy(char* dest, const char* src, int len) +char *APP_CC +g_strncpy(char *dest, const char *src, int len) { - char* rv; + char *rv; - if (src == 0 && dest != 0) - { - dest[0] = 0; - return dest; - } - if (dest == 0 || src == 0) - { - return 0; - } - rv = strncpy(dest, src, len); - dest[len] = 0; - return rv; + if (src == 0 && dest != 0) + { + dest[0] = 0; + return dest; + } + + if (dest == 0 || src == 0) + { + return 0; + } + + rv = strncpy(dest, src, len); + dest[len] = 0; + return rv; } /*****************************************************************************/ /* returns dest */ -char* APP_CC -g_strcat(char* dest, const char* src) +char *APP_CC +g_strcat(char *dest, const char *src) { - if (dest == 0 || src == 0) - { - return dest; - } - return strcat(dest, src); + if (dest == 0 || src == 0) + { + return dest; + } + + return strcat(dest, src); } /*****************************************************************************/ /* if in = 0, return 0 else return newly alloced copy of in */ -char* APP_CC -g_strdup(const char* in) +char *APP_CC +g_strdup(const char *in) { - int len; - char* p; + int len; + char *p; - if (in == 0) - { - return 0; - } - len = g_strlen(in); - p = (char*)g_malloc(len + 1, 0); - if (p != NULL) - { - g_strcpy(p, in); - } - return p; + if (in == 0) + { + return 0; + } + + len = g_strlen(in); + p = (char *)g_malloc(len + 1, 0); + + if (p != NULL) + { + g_strcpy(p, in); + } + + return p; } /*****************************************************************************/ /* if in = 0, return 0 else return newly alloced copy of input string * if the input string is larger than maxlen the returned string will be * truncated. All strings returned will include null termination*/ -char* APP_CC -g_strndup(const char* in, const unsigned int maxlen) +char *APP_CC +g_strndup(const char *in, const unsigned int maxlen) { - int len; - char* p; + int len; + char *p; - if (in == 0) - { - return 0; - } - len = g_strlen(in); - if (len>maxlen) - { - len = maxlen - 1; - } - p = (char*)g_malloc(len + 2, 0); - if (p != NULL) - { - g_strncpy(p, in,len+1); - } - return p; -} -/*****************************************************************************/ -int APP_CC -g_strcmp(const char* c1, const char* c2) -{ - return strcmp(c1, c2); -} - -/*****************************************************************************/ -int APP_CC -g_strncmp(const char* c1, const char* c2, int len) -{ - return strncmp(c1, c2, len); -} - -/*****************************************************************************/ -int APP_CC -g_strcasecmp(const char* c1, const char* c2) -{ -#if defined(_WIN32) - return stricmp(c1, c2); -#else - return strcasecmp(c1, c2); -#endif -} - -/*****************************************************************************/ -int APP_CC -g_strncasecmp(const char* c1, const char* c2, int len) -{ -#if defined(_WIN32) - return strnicmp(c1, c2, len); -#else - return strncasecmp(c1, c2, len); -#endif -} - -/*****************************************************************************/ -int APP_CC -g_atoi(const char* str) -{ - if (str == 0) - { - return 0; - } - return atoi(str); -} - -/*****************************************************************************/ -int APP_CC -g_htoi(char* str) -{ - int len; - int index; - int rv; - int val; - int shift; - - rv = 0; - len = strlen(str); - index = len - 1; - shift = 0; - while (index >= 0) - { - val = 0; - switch (str[index]) + if (in == 0) { - case '1': - val = 1; - break; - case '2': - val = 2; - break; - case '3': - val = 3; - break; - case '4': - val = 4; - break; - case '5': - val = 5; - break; - case '6': - val = 6; - break; - case '7': - val = 7; - break; - case '8': - val = 8; - break; - case '9': - val = 9; - break; - case 'a': - case 'A': - val = 10; - break; - case 'b': - case 'B': - val = 11; - break; - case 'c': - case 'C': - val = 12; - break; - case 'd': - case 'D': - val = 13; - break; - case 'e': - case 'E': - val = 14; - break; - case 'f': - case 'F': - val = 15; - break; + return 0; } - rv = rv | (val << shift); - index--; - shift += 4; - } - return rv; + + len = g_strlen(in); + + if (len > maxlen) + { + len = maxlen - 1; + } + + p = (char *)g_malloc(len + 2, 0); + + if (p != NULL) + { + g_strncpy(p, in, len + 1); + } + + return p; +} +/*****************************************************************************/ +int APP_CC +g_strcmp(const char *c1, const char *c2) +{ + return strcmp(c1, c2); } /*****************************************************************************/ int APP_CC -g_pos(char* str, const char* to_find) +g_strncmp(const char *c1, const char *c2, int len) { - char* pp; - - pp = strstr(str, to_find); - if (pp == 0) - { - return -1; - } - return (pp - str); + return strncmp(c1, c2, len); } /*****************************************************************************/ int APP_CC -g_mbstowcs(twchar* dest, const char* src, int n) +g_strcasecmp(const char *c1, const char *c2) { - wchar_t* ldest; - int rv; - - ldest = (wchar_t*)dest; - rv = mbstowcs(ldest, src, n); - return rv; +#if defined(_WIN32) + return stricmp(c1, c2); +#else + return strcasecmp(c1, c2); +#endif } /*****************************************************************************/ int APP_CC -g_wcstombs(char* dest, const twchar* src, int n) +g_strncasecmp(const char *c1, const char *c2, int len) { - const wchar_t* lsrc; - int rv; +#if defined(_WIN32) + return strnicmp(c1, c2, len); +#else + return strncasecmp(c1, c2, len); +#endif +} - lsrc = (const wchar_t*)src; - rv = wcstombs(dest, lsrc, n); - return rv; +/*****************************************************************************/ +int APP_CC +g_atoi(const char *str) +{ + if (str == 0) + { + return 0; + } + + return atoi(str); +} + +/*****************************************************************************/ +int APP_CC +g_htoi(char *str) +{ + int len; + int index; + int rv; + int val; + int shift; + + rv = 0; + len = strlen(str); + index = len - 1; + shift = 0; + + while (index >= 0) + { + val = 0; + + switch (str[index]) + { + case '1': + val = 1; + break; + case '2': + val = 2; + break; + case '3': + val = 3; + break; + case '4': + val = 4; + break; + case '5': + val = 5; + break; + case '6': + val = 6; + break; + case '7': + val = 7; + break; + case '8': + val = 8; + break; + case '9': + val = 9; + break; + case 'a': + case 'A': + val = 10; + break; + case 'b': + case 'B': + val = 11; + break; + case 'c': + case 'C': + val = 12; + break; + case 'd': + case 'D': + val = 13; + break; + case 'e': + case 'E': + val = 14; + break; + case 'f': + case 'F': + val = 15; + break; + } + + rv = rv | (val << shift); + index--; + shift += 4; + } + + return rv; +} + +/*****************************************************************************/ +int APP_CC +g_pos(char *str, const char *to_find) +{ + char *pp; + + pp = strstr(str, to_find); + + if (pp == 0) + { + return -1; + } + + return (pp - str); +} + +/*****************************************************************************/ +int APP_CC +g_mbstowcs(twchar *dest, const char *src, int n) +{ + wchar_t *ldest; + int rv; + + ldest = (wchar_t *)dest; + rv = mbstowcs(ldest, src, n); + return rv; +} + +/*****************************************************************************/ +int APP_CC +g_wcstombs(char *dest, const twchar *src, int n) +{ + const wchar_t *lsrc; + int rv; + + lsrc = (const wchar_t *)src; + rv = wcstombs(dest, lsrc, n); + return rv; } /*****************************************************************************/ @@ -1845,127 +1997,143 @@ g_wcstombs(char* dest, const twchar* src, int n) /* trim_flags 1 trim left, 2 trim right, 3 trim both, 4 trim through */ /* this will always shorten the string or not change it */ int APP_CC -g_strtrim(char* str, int trim_flags) +g_strtrim(char *str, int trim_flags) { - int index; - int len; - int text1_index; - int got_char; - wchar_t* text; - wchar_t* text1; + int index; + int len; + int text1_index; + int got_char; + wchar_t *text; + wchar_t *text1; - len = mbstowcs(0, str, 0); - if (len < 1) - { + len = mbstowcs(0, str, 0); + + if (len < 1) + { + return 0; + } + + if ((trim_flags < 1) || (trim_flags > 4)) + { + return 1; + } + + text = (wchar_t *)malloc(len * sizeof(wchar_t) + 8); + text1 = (wchar_t *)malloc(len * sizeof(wchar_t) + 8); + text1_index = 0; + mbstowcs(text, str, len + 1); + + switch (trim_flags) + { + case 4: /* trim through */ + + for (index = 0; index < len; index++) + { + if (text[index] > 32) + { + text1[text1_index] = text[index]; + text1_index++; + } + } + + text1[text1_index] = 0; + break; + case 3: /* trim both */ + got_char = 0; + + for (index = 0; index < len; index++) + { + if (got_char) + { + text1[text1_index] = text[index]; + text1_index++; + } + else + { + if (text[index] > 32) + { + text1[text1_index] = text[index]; + text1_index++; + got_char = 1; + } + } + } + + text1[text1_index] = 0; + len = text1_index; + + /* trim right */ + for (index = len - 1; index >= 0; index--) + { + if (text1[index] > 32) + { + break; + } + } + + text1_index = index + 1; + text1[text1_index] = 0; + break; + case 2: /* trim right */ + + /* copy it */ + for (index = 0; index < len; index++) + { + text1[text1_index] = text[index]; + text1_index++; + } + + /* trim right */ + for (index = len - 1; index >= 0; index--) + { + if (text1[index] > 32) + { + break; + } + } + + text1_index = index + 1; + text1[text1_index] = 0; + break; + case 1: /* trim left */ + got_char = 0; + + for (index = 0; index < len; index++) + { + if (got_char) + { + text1[text1_index] = text[index]; + text1_index++; + } + else + { + if (text[index] > 32) + { + text1[text1_index] = text[index]; + text1_index++; + got_char = 1; + } + } + } + + text1[text1_index] = 0; + break; + } + + wcstombs(str, text1, text1_index + 1); + free(text); + free(text1); return 0; - } - if ((trim_flags < 1) || (trim_flags > 4)) - { - return 1; - } - text = (wchar_t*)malloc(len * sizeof(wchar_t) + 8); - text1 = (wchar_t*)malloc(len * sizeof(wchar_t) + 8); - text1_index = 0; - mbstowcs(text, str, len + 1); - switch (trim_flags) - { - case 4: /* trim through */ - for (index = 0; index < len; index++) - { - if (text[index] > 32) - { - text1[text1_index] = text[index]; - text1_index++; - } - } - text1[text1_index] = 0; - break; - case 3: /* trim both */ - got_char = 0; - for (index = 0; index < len; index++) - { - if (got_char) - { - text1[text1_index] = text[index]; - text1_index++; - } - else - { - if (text[index] > 32) - { - text1[text1_index] = text[index]; - text1_index++; - got_char = 1; - } - } - } - text1[text1_index] = 0; - len = text1_index; - /* trim right */ - for (index = len - 1; index >= 0; index--) - { - if (text1[index] > 32) - { - break; - } - } - text1_index = index + 1; - text1[text1_index] = 0; - break; - case 2: /* trim right */ - /* copy it */ - for (index = 0; index < len; index++) - { - text1[text1_index] = text[index]; - text1_index++; - } - /* trim right */ - for (index = len - 1; index >= 0; index--) - { - if (text1[index] > 32) - { - break; - } - } - text1_index = index + 1; - text1[text1_index] = 0; - break; - case 1: /* trim left */ - got_char = 0; - for (index = 0; index < len; index++) - { - if (got_char) - { - text1[text1_index] = text[index]; - text1_index++; - } - else - { - if (text[index] > 32) - { - text1[text1_index] = text[index]; - text1_index++; - got_char = 1; - } - } - } - text1[text1_index] = 0; - break; - } - wcstombs(str, text1, text1_index + 1); - free(text); - free(text1); - return 0; } /*****************************************************************************/ long APP_CC -g_load_library(char* in) +g_load_library(char *in) { #if defined(_WIN32) - return (long)LoadLibraryA(in); + return (long)LoadLibraryA(in); #else - return (long)dlopen(in, RTLD_LOCAL | RTLD_LAZY); + return (long)dlopen(in, RTLD_LOCAL | RTLD_LAZY); #endif } @@ -1973,54 +2141,56 @@ g_load_library(char* in) int APP_CC g_free_library(long lib) { - if (lib == 0) - { - return 0; - } + if (lib == 0) + { + return 0; + } + #if defined(_WIN32) - return FreeLibrary((HMODULE)lib); + return FreeLibrary((HMODULE)lib); #else - return dlclose((void*)lib); + return dlclose((void *)lib); #endif } /*****************************************************************************/ /* returns NULL if not found */ -void* APP_CC -g_get_proc_address(long lib, const char* name) +void *APP_CC +g_get_proc_address(long lib, const char *name) { - if (lib == 0) - { - return 0; - } + if (lib == 0) + { + return 0; + } + #if defined(_WIN32) - return GetProcAddress((HMODULE)lib, name); + return GetProcAddress((HMODULE)lib, name); #else - return dlsym((void*)lib, name); + return dlsym((void *)lib, name); #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC -g_system(char* aexec) +g_system(char *aexec) { #if defined(_WIN32) - return 0; + return 0; #else - return system(aexec); + return system(aexec); #endif } /*****************************************************************************/ /* does not work in win32 */ -char* APP_CC +char *APP_CC g_get_strerror(void) { #if defined(_WIN32) - return 0; + return 0; #else - return strerror(errno); + return strerror(errno); #endif } @@ -2029,43 +2199,43 @@ int APP_CC g_get_errno(void) { #if defined(_WIN32) - return GetLastError(); + return GetLastError(); #else - return errno; + return errno; #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC -g_execvp(const char* p1, char* args[]) +g_execvp(const char *p1, char *args[]) { #if defined(_WIN32) - return 0; + return 0; #else - int rv; + int rv; - g_rm_temp_dir(); - rv = execvp(p1, args); - g_mk_temp_dir(0); - return rv; + g_rm_temp_dir(); + rv = execvp(p1, args); + g_mk_temp_dir(0); + return rv; #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC -g_execlp3(const char* a1, const char* a2, const char* a3) +g_execlp3(const char *a1, const char *a2, const char *a3) { #if defined(_WIN32) - return 0; + return 0; #else - int rv; + int rv; - g_rm_temp_dir(); - rv = execlp(a1, a2, a3, (void*)0); - g_mk_temp_dir(0); - return rv; + g_rm_temp_dir(); + rv = execlp(a1, a2, a3, (void *)0); + g_mk_temp_dir(0); + return rv; #endif } @@ -2076,7 +2246,7 @@ g_signal_child_stop(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGCHLD, func); + signal(SIGCHLD, func); #endif } @@ -2087,7 +2257,7 @@ g_signal_hang_up(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGHUP, func); + signal(SIGHUP, func); #endif } @@ -2098,7 +2268,7 @@ g_signal_user_interrupt(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGINT, func); + signal(SIGINT, func); #endif } @@ -2109,7 +2279,7 @@ g_signal_kill(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGKILL, func); + signal(SIGKILL, func); #endif } @@ -2120,7 +2290,7 @@ g_signal_terminate(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGTERM, func); + signal(SIGTERM, func); #endif } @@ -2131,7 +2301,7 @@ g_signal_pipe(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGPIPE, func); + signal(SIGPIPE, func); #endif } @@ -2142,7 +2312,7 @@ g_signal_usr1(void (*func)(int)) { #if defined(_WIN32) #else - signal(SIGUSR1, func); + signal(SIGUSR1, func); #endif } @@ -2152,16 +2322,18 @@ int APP_CC g_fork(void) { #if defined(_WIN32) - return 0; + return 0; #else - int rv; + int rv; - rv = fork(); - if (rv == 0) /* child */ - { - g_mk_temp_dir(0); - } - return rv; + rv = fork(); + + if (rv == 0) /* child */ + { + g_mk_temp_dir(0); + } + + return rv; #endif } @@ -2171,9 +2343,9 @@ int APP_CC g_setgid(int pid) { #if defined(_WIN32) - return 0; + return 0; #else - return setgid(pid); + return setgid(pid); #endif } @@ -2181,12 +2353,12 @@ g_setgid(int pid) /* returns error, zero is success, non zero is error */ /* does not work in win32 */ int APP_CC -g_initgroups(const char* user, int gid) +g_initgroups(const char *user, int gid) { #if defined(_WIN32) - return 0; + return 0; #else - return initgroups(user, gid); + return initgroups(user, gid); #endif } @@ -2197,9 +2369,9 @@ int APP_CC g_getuid(void) { #if defined(_WIN32) - return 0; + return 0; #else - return getuid(); + return getuid(); #endif } @@ -2210,9 +2382,9 @@ int APP_CC g_setuid(int pid) { #if defined(_WIN32) - return 0; + return 0; #else - return setuid(pid); + return setuid(pid); #endif } @@ -2223,20 +2395,22 @@ int APP_CC g_waitchild(void) { #if defined(_WIN32) - return 0; + return 0; #else - int wstat; - int rv; + int wstat; + int rv; - rv = waitpid(0, &wstat, WNOHANG); - if (rv == -1) - { - if (errno == EINTR) /* signal occurred */ + rv = waitpid(0, &wstat, WNOHANG); + + if (rv == -1) { - rv = 0; + if (errno == EINTR) /* signal occurred */ + { + rv = 0; + } } - } - return rv; + + return rv; #endif } @@ -2247,23 +2421,28 @@ int APP_CC g_waitpid(int pid) { #if defined(_WIN32) - return 0; + return 0; #else - int rv = 0; - if (pid < 0) { - rv = -1; - } - else { - rv = waitpid(pid, 0, 0); - if (rv == -1) + int rv = 0; + + if (pid < 0) { - if (errno == EINTR) /* signal occurred */ - { - rv = 0; - } + rv = -1; } - } - return rv; + else + { + rv = waitpid(pid, 0, 0); + + if (rv == -1) + { + if (errno == EINTR) /* signal occurred */ + { + rv = 0; + } + } + } + + return rv; #endif } @@ -2274,31 +2453,31 @@ g_clearenv(void) { #if defined(_WIN32) #else - environ = 0; + environ = 0; #endif } /*****************************************************************************/ /* does not work in win32 */ int APP_CC -g_setenv(const char* name, const char* value, int rewrite) +g_setenv(const char *name, const char *value, int rewrite) { #if defined(_WIN32) - return 0; + return 0; #else - return setenv(name, value, rewrite); + return setenv(name, value, rewrite); #endif } /*****************************************************************************/ /* does not work in win32 */ -char* APP_CC -g_getenv(const char* name) +char *APP_CC +g_getenv(const char *name) { #if defined(_WIN32) - return 0; + return 0; #else - return getenv(name); + return getenv(name); #endif } @@ -2306,8 +2485,8 @@ g_getenv(const char* name) int APP_CC g_exit(int exit_code) { - _exit(exit_code); - return 0; + _exit(exit_code); + return 0; } /*****************************************************************************/ @@ -2315,9 +2494,9 @@ int APP_CC g_getpid(void) { #if defined(_WIN32) - return (int)GetCurrentProcessId(); + return (int)GetCurrentProcessId(); #else - return (int)getpid(); + return (int)getpid(); #endif } @@ -2327,9 +2506,9 @@ int APP_CC g_sigterm(int pid) { #if defined(_WIN32) - return 0; + return 0; #else - return kill(pid, SIGTERM); + return kill(pid, SIGTERM); #endif } @@ -2337,40 +2516,47 @@ g_sigterm(int pid) /* returns 0 if ok */ /* does not work in win32 */ int APP_CC -g_getuser_info(const char* username, int* gid, int* uid, char* shell, - char* dir, char* gecos) +g_getuser_info(const char *username, int *gid, int *uid, char *shell, + char *dir, char *gecos) { #if defined(_WIN32) - return 1; + return 1; #else - struct passwd* pwd_1; + struct passwd *pwd_1; - pwd_1 = getpwnam(username); - if (pwd_1 != 0) - { - if (gid != 0) + pwd_1 = getpwnam(username); + + if (pwd_1 != 0) { - *gid = pwd_1->pw_gid; + if (gid != 0) + { + *gid = pwd_1->pw_gid; + } + + if (uid != 0) + { + *uid = pwd_1->pw_uid; + } + + if (dir != 0) + { + g_strcpy(dir, pwd_1->pw_dir); + } + + if (shell != 0) + { + g_strcpy(shell, pwd_1->pw_shell); + } + + if (gecos != 0) + { + g_strcpy(gecos, pwd_1->pw_gecos); + } + + return 0; } - if (uid != 0) - { - *uid = pwd_1->pw_uid; - } - if (dir != 0) - { - g_strcpy(dir, pwd_1->pw_dir); - } - if (shell != 0) - { - g_strcpy(shell, pwd_1->pw_shell); - } - if (gecos != 0) - { - g_strcpy(gecos, pwd_1->pw_gecos); - } - return 0; - } - return 1; + + return 1; #endif } @@ -2378,23 +2564,26 @@ g_getuser_info(const char* username, int* gid, int* uid, char* shell, /* returns 0 if ok */ /* does not work in win32 */ int APP_CC -g_getgroup_info(const char* groupname, int* gid) +g_getgroup_info(const char *groupname, int *gid) { #if defined(_WIN32) - return 1; + return 1; #else - struct group* g; + struct group *g; - g = getgrnam(groupname); - if (g != 0) - { - if (gid != 0) + g = getgrnam(groupname); + + if (g != 0) { - *gid = g->gr_gid; + if (gid != 0) + { + *gid = g->gr_gid; + } + + return 0; } - return 0; - } - return 1; + + return 1; #endif } @@ -2403,31 +2592,36 @@ g_getgroup_info(const char* groupname, int* gid) /* if zero is returned, then ok is set */ /* does not work in win32 */ int APP_CC -g_check_user_in_group(const char* username, int gid, int* ok) +g_check_user_in_group(const char *username, int gid, int *ok) { #if defined(_WIN32) - return 1; -#else - struct group* groups; - int i; - - groups = getgrgid(gid); - if (groups == 0) - { return 1; - } - *ok = 0; - i = 0; - while (0 != groups->gr_mem[i]) - { - if (0 == g_strcmp(groups->gr_mem[i], username)) +#else + struct group *groups; + int i; + + groups = getgrgid(gid); + + if (groups == 0) { - *ok = 1; - break; + return 1; } - i++; - } - return 0; + + *ok = 0; + i = 0; + + while (0 != groups->gr_mem[i]) + { + if (0 == g_strcmp(groups->gr_mem[i], username)) + { + *ok = 1; + break; + } + + i++; + } + + return 0; #endif } @@ -2440,9 +2634,9 @@ int APP_CC g_time1(void) { #if defined(_WIN32) - return GetTickCount() / 1000; + return GetTickCount() / 1000; #else - return time(0); + return time(0); #endif } @@ -2453,13 +2647,13 @@ int APP_CC g_time2(void) { #if defined(_WIN32) - return (int)GetTickCount(); + return (int)GetTickCount(); #else - struct tms tm; - clock_t num_ticks = 0; - g_memset(&tm,0,sizeof(struct tms)); - num_ticks = times(&tm); - return (int)(num_ticks * 10); + struct tms tm; + clock_t num_ticks = 0; + g_memset(&tm, 0, sizeof(struct tms)); + num_ticks = times(&tm); + return (int)(num_ticks * 10); #endif } @@ -2470,11 +2664,11 @@ int APP_CC g_time3(void) { #if defined(_WIN32) - return 0; + return 0; #else - struct timeval tp; + struct timeval tp; - gettimeofday(&tp, 0); - return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); + gettimeofday(&tp, 0); + return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); #endif } diff --git a/common/os_calls.h b/common/os_calls.h index 41b221bf..c734c9fe 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -1,26 +1,22 @@ -/* - Copyright (c) 2004-2012 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - generic operating system calls -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * generic operating system calls + */ #if !defined(OS_CALLS_H) #define OS_CALLS_H diff --git a/common/parse.h b/common/parse.h index 9bd6850c..deee7845 100644 --- a/common/parse.h +++ b/common/parse.h @@ -1,30 +1,26 @@ -/* - Copyright (c) 2004-2010 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - Parsing structs and macros - - based on parse.h from rdesktop - this is a super fast stream method, you bet - needed functions g_malloc, g_free, g_memset, g_memcpy -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parsing structs and macros + * + * based on parse.h from rdesktop + * this is a super fast stream method, you bet + * needed functions g_malloc, g_free, g_memset, g_memcpy + */ #if !defined(PARSE_H) #define PARSE_H diff --git a/common/ssl_calls.c b/common/ssl_calls.c index 3d37ed6d..4cb706f3 100644 --- a/common/ssl_calls.c +++ b/common/ssl_calls.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - ssl calls - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ssl calls + */ #include /* needed for openssl headers */ #include @@ -43,197 +41,200 @@ int ssl_init(void) { - SSL_load_error_strings(); - SSL_library_init(); - return 0; + SSL_load_error_strings(); + SSL_library_init(); + return 0; } /*****************************************************************************/ int ssl_finish(void) { - return 0; + return 0; } /* rc4 stuff */ /*****************************************************************************/ -void* APP_CC +void *APP_CC ssl_rc4_info_create(void) { - return g_malloc(sizeof(RC4_KEY), 1); + return g_malloc(sizeof(RC4_KEY), 1); } /*****************************************************************************/ void APP_CC -ssl_rc4_info_delete(void* rc4_info) +ssl_rc4_info_delete(void *rc4_info) { - g_free(rc4_info); + g_free(rc4_info); } /*****************************************************************************/ void APP_CC -ssl_rc4_set_key(void* rc4_info, char* key, int len) +ssl_rc4_set_key(void *rc4_info, char *key, int len) { - RC4_set_key((RC4_KEY*)rc4_info, len, (tui8*)key); + RC4_set_key((RC4_KEY *)rc4_info, len, (tui8 *)key); } /*****************************************************************************/ void APP_CC -ssl_rc4_crypt(void* rc4_info, char* data, int len) +ssl_rc4_crypt(void *rc4_info, char *data, int len) { - RC4((RC4_KEY*)rc4_info, len, (tui8*)data, (tui8*)data); + RC4((RC4_KEY *)rc4_info, len, (tui8 *)data, (tui8 *)data); } /* sha1 stuff */ /*****************************************************************************/ -void* APP_CC +void *APP_CC ssl_sha1_info_create(void) { - return g_malloc(sizeof(SHA_CTX), 1); + return g_malloc(sizeof(SHA_CTX), 1); } /*****************************************************************************/ void APP_CC -ssl_sha1_info_delete(void* sha1_info) +ssl_sha1_info_delete(void *sha1_info) { - g_free(sha1_info); + g_free(sha1_info); } /*****************************************************************************/ void APP_CC -ssl_sha1_clear(void* sha1_info) +ssl_sha1_clear(void *sha1_info) { - SHA1_Init((SHA_CTX*)sha1_info); + SHA1_Init((SHA_CTX *)sha1_info); } /*****************************************************************************/ void APP_CC -ssl_sha1_transform(void* sha1_info, char* data, int len) +ssl_sha1_transform(void *sha1_info, char *data, int len) { - SHA1_Update((SHA_CTX*)sha1_info, data, len); + SHA1_Update((SHA_CTX *)sha1_info, data, len); } /*****************************************************************************/ void APP_CC -ssl_sha1_complete(void* sha1_info, char* data) +ssl_sha1_complete(void *sha1_info, char *data) { - SHA1_Final((tui8*)data, (SHA_CTX*)sha1_info); + SHA1_Final((tui8 *)data, (SHA_CTX *)sha1_info); } /* md5 stuff */ /*****************************************************************************/ -void* APP_CC +void *APP_CC ssl_md5_info_create(void) { - return g_malloc(sizeof(MD5_CTX), 1); + return g_malloc(sizeof(MD5_CTX), 1); } /*****************************************************************************/ void APP_CC -ssl_md5_info_delete(void* md5_info) +ssl_md5_info_delete(void *md5_info) { - g_free(md5_info); + g_free(md5_info); } /*****************************************************************************/ void APP_CC -ssl_md5_clear(void* md5_info) +ssl_md5_clear(void *md5_info) { - MD5_Init((MD5_CTX*)md5_info); + MD5_Init((MD5_CTX *)md5_info); } /*****************************************************************************/ void APP_CC -ssl_md5_transform(void* md5_info, char* data, int len) +ssl_md5_transform(void *md5_info, char *data, int len) { - MD5_Update((MD5_CTX*)md5_info, data, len); + MD5_Update((MD5_CTX *)md5_info, data, len); } /*****************************************************************************/ void APP_CC -ssl_md5_complete(void* md5_info, char* data) +ssl_md5_complete(void *md5_info, char *data) { - MD5_Final((tui8*)data, (MD5_CTX*)md5_info); + MD5_Final((tui8 *)data, (MD5_CTX *)md5_info); } /*****************************************************************************/ static void APP_CC -ssl_reverse_it(char* p, int len) +ssl_reverse_it(char *p, int len) { - int i; - int j; - char temp; + int i; + int j; + char temp; - i = 0; - j = len - 1; - while (i < j) - { - temp = p[i]; - p[i] = p[j]; - p[j] = temp; - i++; - j--; - } + i = 0; + j = len - 1; + + while (i < j) + { + temp = p[i]; + p[i] = p[j]; + p[j] = temp; + i++; + j--; + } } /*****************************************************************************/ int APP_CC -ssl_mod_exp(char* out, int out_len, char* in, int in_len, - char* mod, int mod_len, char* exp, int exp_len) +ssl_mod_exp(char *out, int out_len, char *in, int in_len, + char *mod, int mod_len, char *exp, int exp_len) { - BN_CTX* ctx; - BIGNUM lmod; - BIGNUM lexp; - BIGNUM lin; - BIGNUM lout; - int rv; - char* l_out; - char* l_in; - char* l_mod; - char* l_exp; + BN_CTX *ctx; + BIGNUM lmod; + BIGNUM lexp; + BIGNUM lin; + BIGNUM lout; + int rv; + char *l_out; + char *l_in; + char *l_mod; + char *l_exp; - l_out = (char*)g_malloc(out_len, 1); - l_in = (char*)g_malloc(in_len, 1); - l_mod = (char*)g_malloc(mod_len, 1); - l_exp = (char*)g_malloc(exp_len, 1); - g_memcpy(l_in, in, in_len); - g_memcpy(l_mod, mod, mod_len); - g_memcpy(l_exp, exp, exp_len); - ssl_reverse_it(l_in, in_len); - ssl_reverse_it(l_mod, mod_len); - ssl_reverse_it(l_exp, exp_len); - ctx = BN_CTX_new(); - BN_init(&lmod); - BN_init(&lexp); - BN_init(&lin); - BN_init(&lout); - BN_bin2bn((tui8*)l_mod, mod_len, &lmod); - BN_bin2bn((tui8*)l_exp, exp_len, &lexp); - BN_bin2bn((tui8*)l_in, in_len, &lin); - BN_mod_exp(&lout, &lin, &lexp, &lmod, ctx); - rv = BN_bn2bin(&lout, (tui8*)l_out); - if (rv <= out_len) - { - ssl_reverse_it(l_out, rv); - g_memcpy(out, l_out, out_len); - } - else - { - rv = 0; - } - BN_free(&lin); - BN_free(&lout); - BN_free(&lexp); - BN_free(&lmod); - BN_CTX_free(ctx); - g_free(l_out); - g_free(l_in); - g_free(l_mod); - g_free(l_exp); - return rv; + l_out = (char *)g_malloc(out_len, 1); + l_in = (char *)g_malloc(in_len, 1); + l_mod = (char *)g_malloc(mod_len, 1); + l_exp = (char *)g_malloc(exp_len, 1); + g_memcpy(l_in, in, in_len); + g_memcpy(l_mod, mod, mod_len); + g_memcpy(l_exp, exp, exp_len); + ssl_reverse_it(l_in, in_len); + ssl_reverse_it(l_mod, mod_len); + ssl_reverse_it(l_exp, exp_len); + ctx = BN_CTX_new(); + BN_init(&lmod); + BN_init(&lexp); + BN_init(&lin); + BN_init(&lout); + BN_bin2bn((tui8 *)l_mod, mod_len, &lmod); + BN_bin2bn((tui8 *)l_exp, exp_len, &lexp); + BN_bin2bn((tui8 *)l_in, in_len, &lin); + BN_mod_exp(&lout, &lin, &lexp, &lmod, ctx); + rv = BN_bn2bin(&lout, (tui8 *)l_out); + + if (rv <= out_len) + { + ssl_reverse_it(l_out, rv); + g_memcpy(out, l_out, out_len); + } + else + { + rv = 0; + } + + BN_free(&lin); + BN_free(&lout); + BN_free(&lexp); + BN_free(&lmod); + BN_CTX_free(ctx); + g_free(l_out); + g_free(l_in); + g_free(l_mod); + g_free(l_exp); + return rv; } #if defined(OLD_RSA_GEN1) @@ -242,61 +243,68 @@ ssl_mod_exp(char* out, int out_len, char* in, int in_len, generates a new rsa key exp is passed in and mod and pri are passed out */ int APP_CC -ssl_gen_key_xrdp1(int key_size_in_bits, char* exp, int exp_len, - char* mod, int mod_len, char* pri, int pri_len) +ssl_gen_key_xrdp1(int key_size_in_bits, char *exp, int exp_len, + char *mod, int mod_len, char *pri, int pri_len) { - int my_e; - RSA* my_key; - char* lmod; - char* lpri; - tui8* lexp; - int error; - int len; + int my_e; + RSA *my_key; + char *lmod; + char *lpri; + tui8 *lexp; + int error; + int len; - if ((exp_len != 4) || (mod_len != 64) || (pri_len != 64)) - { - return 1; - } - lmod = (char*)g_malloc(mod_len, 0); - lpri = (char*)g_malloc(pri_len, 0); - lexp = (tui8*)exp; - my_e = lexp[0]; - my_e |= lexp[1] << 8; - my_e |= lexp[2] << 16; - my_e |= lexp[3] << 24; - /* srand is in stdlib.h */ - srand(g_time1()); - my_key = RSA_generate_key(key_size_in_bits, my_e, 0, 0); - error = my_key == 0; - if (error == 0) - { - len = BN_num_bytes(my_key->n); - error = len != mod_len; - } - if (error == 0) - { - BN_bn2bin(my_key->n, (tui8*)lmod); - ssl_reverse_it(lmod, mod_len); - } - if (error == 0) - { - len = BN_num_bytes(my_key->d); - error = len != pri_len; - } - if (error == 0) - { - BN_bn2bin(my_key->d, (tui8*)lpri); - ssl_reverse_it(lpri, pri_len); - } - if (error == 0) - { - g_memcpy(mod, lmod, mod_len); - g_memcpy(pri, lpri, pri_len); - } - RSA_free(my_key); - g_free(lmod); - g_free(lpri); - return error; + if ((exp_len != 4) || (mod_len != 64) || (pri_len != 64)) + { + return 1; + } + + lmod = (char *)g_malloc(mod_len, 0); + lpri = (char *)g_malloc(pri_len, 0); + lexp = (tui8 *)exp; + my_e = lexp[0]; + my_e |= lexp[1] << 8; + my_e |= lexp[2] << 16; + my_e |= lexp[3] << 24; + /* srand is in stdlib.h */ + srand(g_time1()); + my_key = RSA_generate_key(key_size_in_bits, my_e, 0, 0); + error = my_key == 0; + + if (error == 0) + { + len = BN_num_bytes(my_key->n); + error = len != mod_len; + } + + if (error == 0) + { + BN_bn2bin(my_key->n, (tui8 *)lmod); + ssl_reverse_it(lmod, mod_len); + } + + if (error == 0) + { + len = BN_num_bytes(my_key->d); + error = len != pri_len; + } + + if (error == 0) + { + BN_bn2bin(my_key->d, (tui8 *)lpri); + ssl_reverse_it(lpri, pri_len); + } + + if (error == 0) + { + g_memcpy(mod, lmod, mod_len); + g_memcpy(pri, lpri, pri_len); + } + + RSA_free(my_key); + g_free(lmod); + g_free(lpri); + return error; } #else /*****************************************************************************/ @@ -304,60 +312,67 @@ ssl_gen_key_xrdp1(int key_size_in_bits, char* exp, int exp_len, generates a new rsa key exp is passed in and mod and pri are passed out */ int APP_CC -ssl_gen_key_xrdp1(int key_size_in_bits, char* exp, int exp_len, - char* mod, int mod_len, char* pri, int pri_len) +ssl_gen_key_xrdp1(int key_size_in_bits, char *exp, int exp_len, + char *mod, int mod_len, char *pri, int pri_len) { - BIGNUM* my_e; - RSA* my_key; - char* lexp; - char* lmod; - char* lpri; - int error; - int len; + BIGNUM *my_e; + RSA *my_key; + char *lexp; + char *lmod; + char *lpri; + int error; + int len; - if ((exp_len != 4) || (mod_len != 64) || (pri_len != 64)) - { - return 1; - } - lexp = (char*)g_malloc(exp_len, 0); - lmod = (char*)g_malloc(mod_len, 0); - lpri = (char*)g_malloc(pri_len, 0); - g_memcpy(lexp, exp, exp_len); - ssl_reverse_it(lexp, exp_len); - my_e = BN_new(); - BN_bin2bn((tui8*)lexp, exp_len, my_e); - my_key = RSA_new(); - error = RSA_generate_key_ex(my_key, key_size_in_bits, my_e, 0) == 0; - if (error == 0) - { - len = BN_num_bytes(my_key->n); - error = len != mod_len; - } - if (error == 0) - { - BN_bn2bin(my_key->n, (tui8*)lmod); - ssl_reverse_it(lmod, mod_len); - } - if (error == 0) - { - len = BN_num_bytes(my_key->d); - error = len != pri_len; - } - if (error == 0) - { - BN_bn2bin(my_key->d, (tui8*)lpri); - ssl_reverse_it(lpri, pri_len); - } - if (error == 0) - { - g_memcpy(mod, lmod, mod_len); - g_memcpy(pri, lpri, pri_len); - } - BN_free(my_e); - RSA_free(my_key); - g_free(lexp); - g_free(lmod); - g_free(lpri); - return error; + if ((exp_len != 4) || (mod_len != 64) || (pri_len != 64)) + { + return 1; + } + + lexp = (char *)g_malloc(exp_len, 0); + lmod = (char *)g_malloc(mod_len, 0); + lpri = (char *)g_malloc(pri_len, 0); + g_memcpy(lexp, exp, exp_len); + ssl_reverse_it(lexp, exp_len); + my_e = BN_new(); + BN_bin2bn((tui8 *)lexp, exp_len, my_e); + my_key = RSA_new(); + error = RSA_generate_key_ex(my_key, key_size_in_bits, my_e, 0) == 0; + + if (error == 0) + { + len = BN_num_bytes(my_key->n); + error = len != mod_len; + } + + if (error == 0) + { + BN_bn2bin(my_key->n, (tui8 *)lmod); + ssl_reverse_it(lmod, mod_len); + } + + if (error == 0) + { + len = BN_num_bytes(my_key->d); + error = len != pri_len; + } + + if (error == 0) + { + BN_bn2bin(my_key->d, (tui8 *)lpri); + ssl_reverse_it(lpri, pri_len); + } + + if (error == 0) + { + g_memcpy(mod, lmod, mod_len); + g_memcpy(pri, lpri, pri_len); + } + + BN_free(my_e); + RSA_free(my_key); + g_free(lexp); + g_free(lmod); + g_free(lpri); + return error; } #endif diff --git a/common/ssl_calls.h b/common/ssl_calls.h index d78bdb0b..f4a63155 100644 --- a/common/ssl_calls.h +++ b/common/ssl_calls.h @@ -1,22 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #if !defined(SSL_CALLS_H) #define SSL_CALLS_H diff --git a/common/thread_calls.c b/common/thread_calls.c index 80856fd8..ad944d02 100644 --- a/common/thread_calls.c +++ b/common/thread_calls.c @@ -1,27 +1,22 @@ -/* - Copyright (c) 2004-2010 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - thread calls - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * thread calls + */ #if defined(_WIN32) #include @@ -38,33 +33,36 @@ /* returns error */ #if defined(_WIN32) int APP_CC -tc_thread_create(unsigned long (__stdcall * start_routine)(void*), void* arg) +tc_thread_create(unsigned long (__stdcall *start_routine)(void *), void *arg) { - int rv = 0; - DWORD thread_id = 0; - HANDLE thread = (HANDLE)0; + int rv = 0; + DWORD thread_id = 0; + HANDLE thread = (HANDLE)0; - /* CreateThread returns handle or zero on error */ - thread = CreateThread(0, 0, start_routine, arg, 0, &thread_id); - rv = !thread; - CloseHandle(thread); - return rv; + /* CreateThread returns handle or zero on error */ + thread = CreateThread(0, 0, start_routine, arg, 0, &thread_id); + rv = !thread; + CloseHandle(thread); + return rv; } #else int APP_CC -tc_thread_create(void* (* start_routine)(void *), void* arg) +tc_thread_create(void * (* start_routine)(void *), void *arg) { - int rv = 0; - pthread_t thread = (pthread_t)0; + int rv = 0; + pthread_t thread = (pthread_t)0; - g_memset(&thread, 0x00, sizeof(pthread_t)); + g_memset(&thread, 0x00, sizeof(pthread_t)); - /* pthread_create returns error */ - rv = pthread_create(&thread, 0, start_routine, arg); - if (!rv) { - rv = pthread_detach(thread); - } - return rv; + /* pthread_create returns error */ + rv = pthread_create(&thread, 0, start_routine, arg); + + if (!rv) + { + rv = pthread_detach(thread); + } + + return rv; } #endif @@ -73,9 +71,9 @@ tbus APP_CC tc_get_threadid(void) { #if defined(_WIN32) - return (tbus)GetCurrentThreadId(); + return (tbus)GetCurrentThreadId(); #else - return (tbus)pthread_self(); + return (tbus)pthread_self(); #endif } @@ -85,9 +83,9 @@ int APP_CC tc_threadid_equal(tbus tid1, tbus tid2) { #if defined(_WIN32) - return tid1 == tid2; + return tid1 == tid2; #else - return pthread_equal((pthread_t)tid1, (pthread_t)tid2); + return pthread_equal((pthread_t)tid1, (pthread_t)tid2); #endif } @@ -96,13 +94,13 @@ tbus APP_CC tc_mutex_create(void) { #if defined(_WIN32) - return (tbus)CreateMutex(0, 0, 0); + return (tbus)CreateMutex(0, 0, 0); #else - pthread_mutex_t* lmutex; + pthread_mutex_t *lmutex; - lmutex = (pthread_mutex_t*)g_malloc(sizeof(pthread_mutex_t), 0); - pthread_mutex_init(lmutex, 0); - return (tbus)lmutex; + lmutex = (pthread_mutex_t *)g_malloc(sizeof(pthread_mutex_t), 0); + pthread_mutex_init(lmutex, 0); + return (tbus)lmutex; #endif } @@ -111,13 +109,13 @@ void APP_CC tc_mutex_delete(tbus mutex) { #if defined(_WIN32) - CloseHandle((HANDLE)mutex); + CloseHandle((HANDLE)mutex); #else - pthread_mutex_t* lmutex; + pthread_mutex_t *lmutex; - lmutex = (pthread_mutex_t*)mutex; - pthread_mutex_destroy(lmutex); - g_free(lmutex); + lmutex = (pthread_mutex_t *)mutex; + pthread_mutex_destroy(lmutex); + g_free(lmutex); #endif } @@ -126,11 +124,11 @@ int APP_CC tc_mutex_lock(tbus mutex) { #if defined(_WIN32) - WaitForSingleObject((HANDLE)mutex, INFINITE); - return 0; + WaitForSingleObject((HANDLE)mutex, INFINITE); + return 0; #else - pthread_mutex_lock((pthread_mutex_t*)mutex); - return 0; + pthread_mutex_lock((pthread_mutex_t *)mutex); + return 0; #endif } @@ -138,15 +136,18 @@ tc_mutex_lock(tbus mutex) int APP_CC tc_mutex_unlock(tbus mutex) { - int rv = 0; + int rv = 0; #if defined(_WIN32) - ReleaseMutex((HANDLE)mutex); + ReleaseMutex((HANDLE)mutex); #else - if (mutex != 0) { - rv = pthread_mutex_unlock((pthread_mutex_t *)mutex); - } + + if (mutex != 0) + { + rv = pthread_mutex_unlock((pthread_mutex_t *)mutex); + } + #endif - return rv; + return rv; } /*****************************************************************************/ @@ -154,16 +155,16 @@ tbus APP_CC tc_sem_create(int init_count) { #if defined(_WIN32) - HANDLE sem; + HANDLE sem; - sem = CreateSemaphore(0, init_count, init_count + 10, 0); - return (tbus)sem; + sem = CreateSemaphore(0, init_count, init_count + 10, 0); + return (tbus)sem; #else - sem_t * sem = (sem_t *)NULL; + sem_t *sem = (sem_t *)NULL; - sem = (sem_t *)g_malloc(sizeof(sem_t), 0); - sem_init(sem, 0, init_count); - return (tbus)sem; + sem = (sem_t *)g_malloc(sizeof(sem_t), 0); + sem_init(sem, 0, init_count); + return (tbus)sem; #endif } @@ -172,13 +173,13 @@ void APP_CC tc_sem_delete(tbus sem) { #if defined(_WIN32) - CloseHandle((HANDLE)sem); + CloseHandle((HANDLE)sem); #else - sem_t* lsem; + sem_t *lsem; - lsem = (sem_t*)sem; - sem_destroy(lsem); - g_free(lsem); + lsem = (sem_t *)sem; + sem_destroy(lsem); + g_free(lsem); #endif } @@ -187,11 +188,11 @@ int APP_CC tc_sem_dec(tbus sem) { #if defined(_WIN32) - WaitForSingleObject((HANDLE)sem, INFINITE); - return 0; + WaitForSingleObject((HANDLE)sem, INFINITE); + return 0; #else - sem_wait((sem_t*)sem); - return 0; + sem_wait((sem_t *)sem); + return 0; #endif } @@ -200,10 +201,10 @@ int APP_CC tc_sem_inc(tbus sem) { #if defined(_WIN32) - ReleaseSemaphore((HANDLE)sem, 1, 0); - return 0; + ReleaseSemaphore((HANDLE)sem, 1, 0); + return 0; #else - sem_post((sem_t*)sem); - return 0; + sem_post((sem_t *)sem); + return 0; #endif } diff --git a/common/thread_calls.h b/common/thread_calls.h index cc40a7d9..0c853d22 100644 --- a/common/thread_calls.h +++ b/common/thread_calls.h @@ -1,27 +1,22 @@ -/* - Copyright (c) 2004-2010 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - thread calls - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * thread calls + */ #if !defined(THREAD_CALLS_H) #define THREAD_CALLS_H diff --git a/common/trans.c b/common/trans.c index 6b762d00..c287d310 100644 --- a/common/trans.c +++ b/common/trans.c @@ -1,27 +1,22 @@ -/* - Copyright (c) 2008-2010 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - generic transport - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * generic transport + */ #include "os_calls.h" #include "trans.h" @@ -29,394 +24,440 @@ #include "parse.h" /*****************************************************************************/ -struct trans* APP_CC +struct trans *APP_CC trans_create(int mode, int in_size, int out_size) { - struct trans* self = (struct trans *)NULL; + struct trans *self = (struct trans *)NULL; - self = (struct trans*)g_malloc(sizeof(struct trans), 1); - if (self != NULL) { - make_stream(self->in_s); - init_stream(self->in_s, in_size); - make_stream(self->out_s); - init_stream(self->out_s, out_size); - self->mode = mode; - } - return self; + self = (struct trans *)g_malloc(sizeof(struct trans), 1); + + if (self != NULL) + { + make_stream(self->in_s); + init_stream(self->in_s, in_size); + make_stream(self->out_s); + init_stream(self->out_s, out_size); + self->mode = mode; + } + + return self; } /*****************************************************************************/ void APP_CC -trans_delete(struct trans* self) +trans_delete(struct trans *self) { - if (self == 0) - { - return; - } - free_stream(self->in_s); - free_stream(self->out_s); - if (self->sck > 0) { - g_tcp_close(self->sck); - } - self->sck = 0; - if (self->listen_filename != 0) - { - g_file_delete(self->listen_filename); - g_free(self->listen_filename); - } - g_free(self); -} - -/*****************************************************************************/ -int APP_CC -trans_get_wait_objs(struct trans* self, tbus* objs, int* count) -{ - if (self == 0) - { - return 1; - } - if (self->status != TRANS_STATUS_UP) - { - return 1; - } - objs[*count] = self->sck; - (*count)++; - return 0; -} - -/*****************************************************************************/ -int APP_CC -trans_check_wait_objs(struct trans* self) -{ - tbus in_sck = (tbus)0; - struct trans* in_trans = (struct trans *)NULL; - int read_bytes = 0; - int to_read = 0; - int read_so_far = 0; - int rv = 0; - - if (self == 0) - { - return 1; - } - if (self->status != TRANS_STATUS_UP) - { - return 1; - } - rv = 0; - if (self->type1 == TRANS_TYPE_LISTENER) /* listening */ - { - if (g_tcp_can_recv(self->sck, 0)) + if (self == 0) { - in_sck = g_tcp_accept(self->sck); - if (in_sck == -1) - { - if (g_tcp_last_error_would_block(self->sck)) - { - /* ok, but shouldn't happen */ - } - else - { - /* error */ - self->status = TRANS_STATUS_DOWN; - return 1; - } - } - if (in_sck != -1) - { - if (self->trans_conn_in != 0) /* is function assigned */ - { - in_trans = trans_create(self->mode, self->in_s->size, - self->out_s->size); - in_trans->sck = in_sck; - in_trans->type1 = TRANS_TYPE_SERVER; - in_trans->status = TRANS_STATUS_UP; - if (self->trans_conn_in(self, in_trans) != 0) - { - trans_delete(in_trans); - } - } - else - { - g_tcp_close(in_sck); - } - } + return; } - } - else /* connected server or client (2 or 3) */ - { - if (g_tcp_can_recv(self->sck, 0)) + + free_stream(self->in_s); + free_stream(self->out_s); + + if (self->sck > 0) { - read_so_far = (int)(self->in_s->end - self->in_s->data); - to_read = self->header_size - read_so_far; - if (to_read > 0) - { - read_bytes = g_tcp_recv(self->sck, self->in_s->end, to_read, 0); - if (read_bytes == -1) + g_tcp_close(self->sck); + } + + self->sck = 0; + + if (self->listen_filename != 0) + { + g_file_delete(self->listen_filename); + g_free(self->listen_filename); + } + + g_free(self); +} + +/*****************************************************************************/ +int APP_CC +trans_get_wait_objs(struct trans *self, tbus *objs, int *count) +{ + if (self == 0) + { + return 1; + } + + if (self->status != TRANS_STATUS_UP) + { + return 1; + } + + objs[*count] = self->sck; + (*count)++; + return 0; +} + +/*****************************************************************************/ +int APP_CC +trans_check_wait_objs(struct trans *self) +{ + tbus in_sck = (tbus)0; + struct trans *in_trans = (struct trans *)NULL; + int read_bytes = 0; + int to_read = 0; + int read_so_far = 0; + int rv = 0; + + if (self == 0) + { + return 1; + } + + if (self->status != TRANS_STATUS_UP) + { + return 1; + } + + rv = 0; + + if (self->type1 == TRANS_TYPE_LISTENER) /* listening */ + { + if (g_tcp_can_recv(self->sck, 0)) + { + in_sck = g_tcp_accept(self->sck); + + if (in_sck == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + /* ok, but shouldn't happen */ + } + else + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 1; + } + } + + if (in_sck != -1) + { + if (self->trans_conn_in != 0) /* is function assigned */ + { + in_trans = trans_create(self->mode, self->in_s->size, + self->out_s->size); + in_trans->sck = in_sck; + in_trans->type1 = TRANS_TYPE_SERVER; + in_trans->status = TRANS_STATUS_UP; + + if (self->trans_conn_in(self, in_trans) != 0) + { + trans_delete(in_trans); + } + } + else + { + g_tcp_close(in_sck); + } + } + } + } + else /* connected server or client (2 or 3) */ + { + if (g_tcp_can_recv(self->sck, 0)) + { + read_so_far = (int)(self->in_s->end - self->in_s->data); + to_read = self->header_size - read_so_far; + + if (to_read > 0) + { + read_bytes = g_tcp_recv(self->sck, self->in_s->end, to_read, 0); + + if (read_bytes == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + /* ok, but shouldn't happen */ + } + else + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 1; + } + } + else if (read_bytes == 0) + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 1; + } + else + { + self->in_s->end += read_bytes; + } + } + + read_so_far = (int)(self->in_s->end - self->in_s->data); + + if (read_so_far == self->header_size) + { + if (self->trans_data_in != 0) + { + rv = self->trans_data_in(self); + init_stream(self->in_s, 0); + } + } + } + } + + return rv; +} + +/*****************************************************************************/ +int APP_CC +trans_force_read_s(struct trans *self, struct stream *in_s, int size) +{ + int rcvd; + + if (self->status != TRANS_STATUS_UP) + { + return 1; + } + + while (size > 0) + { + rcvd = g_tcp_recv(self->sck, in_s->end, size, 0); + + if (rcvd == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + if (!g_tcp_can_recv(self->sck, 10)) + { + /* check for term here */ + } + } + else + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 1; + } + } + else if (rcvd == 0) { - if (g_tcp_last_error_would_block(self->sck)) - { - /* ok, but shouldn't happen */ - } - else - { /* error */ self->status = TRANS_STATUS_DOWN; return 1; - } - } - else if (read_bytes == 0) - { - /* error */ - self->status = TRANS_STATUS_DOWN; - return 1; } else { - self->in_s->end += read_bytes; + in_s->end += rcvd; + size -= rcvd; } - } - read_so_far = (int)(self->in_s->end - self->in_s->data); - if (read_so_far == self->header_size) - { - if (self->trans_data_in != 0) - { - rv = self->trans_data_in(self); - init_stream(self->in_s, 0); - } - } } - } - return rv; + + return 0; } /*****************************************************************************/ int APP_CC -trans_force_read_s(struct trans* self, struct stream* in_s, int size) +trans_force_read(struct trans *self, int size) { - int rcvd; + return trans_force_read_s(self, self->in_s, size); +} - if (self->status != TRANS_STATUS_UP) - { - return 1; - } - while (size > 0) - { - rcvd = g_tcp_recv(self->sck, in_s->end, size, 0); - if (rcvd == -1) +/*****************************************************************************/ +int APP_CC +trans_force_write_s(struct trans *self, struct stream *out_s) +{ + int size; + int total; + int sent; + + if (self->status != TRANS_STATUS_UP) { - if (g_tcp_last_error_would_block(self->sck)) - { - if (!g_tcp_can_recv(self->sck, 10)) - { - /* check for term here */ - } - } - else - { - /* error */ - self->status = TRANS_STATUS_DOWN; return 1; - } } - else if (rcvd == 0) - { - /* error */ - self->status = TRANS_STATUS_DOWN; - return 1; - } - else - { - in_s->end += rcvd; - size -= rcvd; - } - } - return 0; -} -/*****************************************************************************/ -int APP_CC -trans_force_read(struct trans* self, int size) -{ - return trans_force_read_s(self, self->in_s, size); -} + size = (int)(out_s->end - out_s->data); + total = 0; -/*****************************************************************************/ -int APP_CC -trans_force_write_s(struct trans* self, struct stream* out_s) -{ - int size; - int total; - int sent; - - if (self->status != TRANS_STATUS_UP) - { - return 1; - } - size = (int)(out_s->end - out_s->data); - total = 0; - while (total < size) - { - sent = g_tcp_send(self->sck, out_s->data + total, size - total, 0); - if (sent == -1) + while (total < size) { - if (g_tcp_last_error_would_block(self->sck)) - { - if (!g_tcp_can_send(self->sck, 10)) + sent = g_tcp_send(self->sck, out_s->data + total, size - total, 0); + + if (sent == -1) { - /* check for term here */ + if (g_tcp_last_error_would_block(self->sck)) + { + if (!g_tcp_can_send(self->sck, 10)) + { + /* check for term here */ + } + } + else + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 1; + } + } + else if (sent == 0) + { + /* error */ + self->status = TRANS_STATUS_DOWN; + return 1; + } + else + { + total = total + sent; } - } - else - { - /* error */ - self->status = TRANS_STATUS_DOWN; - return 1; - } } - else if (sent == 0) - { - /* error */ - self->status = TRANS_STATUS_DOWN; - return 1; - } - else - { - total = total + sent; - } - } - return 0; + + return 0; } /*****************************************************************************/ int APP_CC -trans_force_write(struct trans* self) +trans_force_write(struct trans *self) { - return trans_force_write_s(self, self->out_s); + return trans_force_write_s(self, self->out_s); } /*****************************************************************************/ int APP_CC -trans_connect(struct trans* self, const char* server, const char* port, +trans_connect(struct trans *self, const char *server, const char *port, int timeout) { - int error; + int error; - if (self->sck != 0) - { - g_tcp_close(self->sck); - } - if (self->mode == TRANS_MODE_TCP) /* tcp */ - { - self->sck = g_tcp_socket(); - g_tcp_set_non_blocking(self->sck); - error = g_tcp_connect(self->sck, server, port); - } - else if (self->mode == TRANS_MODE_UNIX) /* unix socket */ - { - self->sck = g_tcp_local_socket(); - g_tcp_set_non_blocking(self->sck); - error = g_tcp_local_connect(self->sck, port); - } - else - { - self->status = TRANS_STATUS_DOWN; - return 1; - } - if (error == -1) - { - if (g_tcp_last_error_would_block(self->sck)) + if (self->sck != 0) { - if (g_tcp_can_send(self->sck, timeout)) - { - self->status = TRANS_STATUS_UP; /* ok */ - self->type1 = TRANS_TYPE_CLIENT; /* client */ - return 0; - } + g_tcp_close(self->sck); } - return 1; - } - self->status = TRANS_STATUS_UP; /* ok */ - self->type1 = TRANS_TYPE_CLIENT; /* client */ - return 0; + + if (self->mode == TRANS_MODE_TCP) /* tcp */ + { + self->sck = g_tcp_socket(); + g_tcp_set_non_blocking(self->sck); + error = g_tcp_connect(self->sck, server, port); + } + else if (self->mode == TRANS_MODE_UNIX) /* unix socket */ + { + self->sck = g_tcp_local_socket(); + g_tcp_set_non_blocking(self->sck); + error = g_tcp_local_connect(self->sck, port); + } + else + { + self->status = TRANS_STATUS_DOWN; + return 1; + } + + if (error == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + if (g_tcp_can_send(self->sck, timeout)) + { + self->status = TRANS_STATUS_UP; /* ok */ + self->type1 = TRANS_TYPE_CLIENT; /* client */ + return 0; + } + } + + return 1; + } + + self->status = TRANS_STATUS_UP; /* ok */ + self->type1 = TRANS_TYPE_CLIENT; /* client */ + return 0; } /*****************************************************************************/ int APP_CC -trans_listen_address(struct trans* self, char* port, const char* address) +trans_listen_address(struct trans *self, char *port, const char *address) { - if (self->sck != 0) - { - g_tcp_close(self->sck); - } - if (self->mode == TRANS_MODE_TCP) /* tcp */ - { - self->sck = g_tcp_socket(); - g_tcp_set_non_blocking(self->sck); - if (g_tcp_bind_address(self->sck, port, address) == 0) + if (self->sck != 0) { - if (g_tcp_listen(self->sck) == 0) - { - self->status = TRANS_STATUS_UP; /* ok */ - self->type1 = TRANS_TYPE_LISTENER; /* listener */ - return 0; - } + g_tcp_close(self->sck); } - } - else if (self->mode == TRANS_MODE_UNIX) /* unix socket */ - { - g_free(self->listen_filename); - self->listen_filename = 0; - g_file_delete(port); - self->sck = g_tcp_local_socket(); - g_tcp_set_non_blocking(self->sck); - if (g_tcp_local_bind(self->sck, port) == 0) + + if (self->mode == TRANS_MODE_TCP) /* tcp */ { - self->listen_filename = g_strdup(port); - if (g_tcp_listen(self->sck) == 0) - { - g_chmod_hex(port, 0xffff); - self->status = TRANS_STATUS_UP; /* ok */ - self->type1 = TRANS_TYPE_LISTENER; /* listener */ - return 0; - } + self->sck = g_tcp_socket(); + g_tcp_set_non_blocking(self->sck); + + if (g_tcp_bind_address(self->sck, port, address) == 0) + { + if (g_tcp_listen(self->sck) == 0) + { + self->status = TRANS_STATUS_UP; /* ok */ + self->type1 = TRANS_TYPE_LISTENER; /* listener */ + return 0; + } + } } - } - return 1; + else if (self->mode == TRANS_MODE_UNIX) /* unix socket */ + { + g_free(self->listen_filename); + self->listen_filename = 0; + g_file_delete(port); + self->sck = g_tcp_local_socket(); + g_tcp_set_non_blocking(self->sck); + + if (g_tcp_local_bind(self->sck, port) == 0) + { + self->listen_filename = g_strdup(port); + + if (g_tcp_listen(self->sck) == 0) + { + g_chmod_hex(port, 0xffff); + self->status = TRANS_STATUS_UP; /* ok */ + self->type1 = TRANS_TYPE_LISTENER; /* listener */ + return 0; + } + } + } + + return 1; } /*****************************************************************************/ int APP_CC -trans_listen(struct trans* self, char* port) +trans_listen(struct trans *self, char *port) { - return trans_listen_address(self, port, "0.0.0.0"); + return trans_listen_address(self, port, "0.0.0.0"); } /*****************************************************************************/ -struct stream* APP_CC -trans_get_in_s(struct trans* self) +struct stream *APP_CC +trans_get_in_s(struct trans *self) { - struct stream * rv = (struct stream *)NULL; - if (self == NULL) { - rv = (struct stream *)NULL; - } - else { - rv = self->in_s; - } - return rv; + struct stream *rv = (struct stream *)NULL; + + if (self == NULL) + { + rv = (struct stream *)NULL; + } + else + { + rv = self->in_s; + } + + return rv; } /*****************************************************************************/ -struct stream* APP_CC -trans_get_out_s(struct trans* self, int size) +struct stream *APP_CC +trans_get_out_s(struct trans *self, int size) { - struct stream * rv = (struct stream *)NULL; - if (self == NULL) { - rv = (struct stream *)NULL; - } - else { - init_stream(self->out_s, size); - rv = self->out_s; - } - return rv; + struct stream *rv = (struct stream *)NULL; + + if (self == NULL) + { + rv = (struct stream *)NULL; + } + else + { + init_stream(self->out_s, size); + rv = self->out_s; + } + + return rv; } diff --git a/common/trans.h b/common/trans.h index 8e8d942a..36d08a7c 100644 --- a/common/trans.h +++ b/common/trans.h @@ -1,27 +1,22 @@ -/* - Copyright (c) 2008-2010 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - generic transport - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * generic transport + */ #if !defined(TRANS_H) #define TRANS_H diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index f95543a3..596177c4 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -1,27 +1,22 @@ -/* - Copyright (c) 2012 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - xrdp / xserver info / caps - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * xrdp / xserver info / caps + */ #if !defined(XRDP_CLIENT_INFO_H) #define XRDP_CLIENT_INFO_H diff --git a/fontdump/fontdump.c b/fontdump/fontdump.c index 34bdffdc..03609cf0 100755 --- a/fontdump/fontdump.c +++ b/fontdump/fontdump.c @@ -1,3 +1,20 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include @@ -25,426 +42,485 @@ static int g_running = 0; int check_messages(void) { - MSG msg; + MSG msg; - while (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) - { - GetMessage(&msg, NULL, 0, 0); - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return 0; + while (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) + { + GetMessage(&msg, NULL, 0, 0); + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; } /*****************************************************************************/ static int -msg(char* msg1, ...) +msg(char *msg1, ...) { - va_list ap; - char text1[512]; + va_list ap; + char text1[512]; - va_start(ap, msg1); - vsnprintf(text1, 511, msg1, ap); - SendMessageA(g_lb, LB_ADDSTRING, 0, (LPARAM)text1); - va_end(ap); - return 0; + va_start(ap, msg1); + vsnprintf(text1, 511, msg1, ap); + SendMessageA(g_lb, LB_ADDSTRING, 0, (LPARAM)text1); + va_end(ap); + return 0; } /*****************************************************************************/ static int show_last_error(void) { - LPVOID lpMsgBuf; - - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&lpMsgBuf, 0, NULL); - msg("GetLastError - %s", lpMsgBuf); - LocalFree(lpMsgBuf); - return 0; + LPVOID lpMsgBuf; + + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&lpMsgBuf, 0, NULL); + msg("GetLastError - %s", lpMsgBuf); + LocalFree(lpMsgBuf); + return 0; } /*****************************************************************************/ static int font_dump(void) { - HDC dc; - HDC dc1; - RECT rect; - HBRUSH brush; - HGDIOBJ saved; - HBITMAP bitmap; - BITMAPINFO bi; - char* bits; - ABC abc; - SIZE sz; - char filename[256]; - TCHAR text[256]; - char zero1; - char* bmtext; - int bmtextindex; - int fd; - int x1; - int strlen1; - int index1; - int index2; - int len; - int pixel; - int red; - int green; - int blue; - int width; - int height; - int roller; - int outlen; - tui8 b1; - short x2; + HDC dc; + HDC dc1; + RECT rect; + HBRUSH brush; + HGDIOBJ saved; + HBITMAP bitmap; + BITMAPINFO bi; + char *bits; + ABC abc; + SIZE sz; + char filename[256]; + TCHAR text[256]; + char zero1; + char *bmtext; + int bmtextindex; + int fd; + int x1; + int strlen1; + int index1; + int index2; + int len; + int pixel; + int red; + int green; + int blue; + int width; + int height; + int roller; + int outlen; + tui8 b1; + short x2; - if (g_running) - { - return 0; - } - g_running = 1; - msg("starting"); - g_font_name[0] = 0; - SendMessageA(g_font_list, WM_GETTEXT, 255, (LPARAM)g_font_name); - if (g_strlen(g_font_name) == 0) - { - msg("error font not set"); - g_running = 0; - return 1; - } - dc = GetDC(g_wnd); - height = -MulDiv(g_font_size, GetDeviceCaps(dc, LOGPIXELSY), 72); - g_font = CreateFontA(height, 0, 0, 0, FW_DONTCARE, 0, 0, 0, 0, 0, 0, - 0, 0, g_font_name); - ReleaseDC(g_wnd, dc); - if (g_font == 0) - { - msg("error - Font creation failed"); - } - zero1 = 0; - g_snprintf(filename, 255, "%s-%d.fv1", g_font_name, g_font_size); - msg("creating file %s", filename); - g_file_delete(filename); - fd = g_file_open(filename); - g_file_write(fd, "FNT1", 4); - strlen1 = g_strlen(g_font_name); - g_file_write(fd, g_font_name, strlen1); - x1 = strlen1; - while (x1 < 32) - { - g_file_write(fd, &zero1, 1); - x1++; - } - x2 = g_font_size; /* font size */ - g_file_write(fd, (char*)&x2, 2); - x2 = 1; /* style */ - g_file_write(fd, (char*)&x2, 2); - /* pad */ - index1 = 0; - while (index1 < 8) - { - g_file_write(fd, &zero1, 1); - index1++; - } - for (x1 = 32; x1 < 0x4e00; x1++) - { - check_messages(); - dc = GetWindowDC(g_wnd); - saved = SelectObject(dc, g_font); - if (!GetCharABCWidths(dc, x1, x1, &abc)) + if (g_running) { - show_last_error(); + return 0; } - text[0] = (TCHAR)x1; - text[1] = 0; - if (!GetTextExtentPoint32(dc, text, 1, &sz)) + + g_running = 1; + msg("starting"); + g_font_name[0] = 0; + SendMessageA(g_font_list, WM_GETTEXT, 255, (LPARAM)g_font_name); + + if (g_strlen(g_font_name) == 0) { - show_last_error(); + msg("error font not set"); + g_running = 0; + return 1; } - SelectObject(dc, saved); + + dc = GetDC(g_wnd); + height = -MulDiv(g_font_size, GetDeviceCaps(dc, LOGPIXELSY), 72); + g_font = CreateFontA(height, 0, 0, 0, FW_DONTCARE, 0, 0, 0, 0, 0, 0, + 0, 0, g_font_name); ReleaseDC(g_wnd, dc); - if ((sz.cx > 0) && (sz.cy > 0)) + + if (g_font == 0) + { + msg("error - Font creation failed"); + } + + zero1 = 0; + g_snprintf(filename, 255, "%s-%d.fv1", g_font_name, g_font_size); + msg("creating file %s", filename); + g_file_delete(filename); + fd = g_file_open(filename); + g_file_write(fd, "FNT1", 4); + strlen1 = g_strlen(g_font_name); + g_file_write(fd, g_font_name, strlen1); + x1 = strlen1; + + while (x1 < 32) + { + g_file_write(fd, &zero1, 1); + x1++; + } + + x2 = g_font_size; /* font size */ + g_file_write(fd, (char *)&x2, 2); + x2 = 1; /* style */ + g_file_write(fd, (char *)&x2, 2); + /* pad */ + index1 = 0; + + while (index1 < 8) { - dc = GetWindowDC(g_wnd); - saved = SelectObject(dc, g_font); - SetBkColor(dc, RGB(255, 255, 255)); - if (!ExtTextOut(dc, 50, 50, ETO_OPAQUE, 0, text, 1, 0)) - { - show_last_error(); - } - SelectObject(dc, saved); - ReleaseDC(g_wnd, dc); - Sleep(10); - /* width */ - x2 = abc.abcB; - g_file_write(fd, (char*)&x2, 2); - /* height */ - x2 = sz.cy; - g_file_write(fd, (char*)&x2, 2); - /* baseline */ - x2 = -sz.cy; - g_file_write(fd, (char*)&x2, 2); - /* offset */ - x2 = abc.abcA; - g_file_write(fd, (char*)&x2, 2); - /* incby */ - x2 = sz.cx; - g_file_write(fd, (char*)&x2, 2); - /* pad */ - index1 = 0; - while (index1 < 6) - { g_file_write(fd, &zero1, 1); index1++; - } - dc = GetWindowDC(g_wnd); - rect.left = 50 + abc.abcA; - rect.top = 50; - rect.right = rect.left + abc.abcB; - rect.bottom = rect.top + sz.cy; - memset(&bi, 0, sizeof(bi)); - width = (abc.abcB + 7) & (~7); - height = sz.cy; - bi.bmiHeader.biSize = sizeof(bi.bmiHeader); - bi.bmiHeader.biWidth = width; - bi.bmiHeader.biHeight = height; - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = 32; - bitmap = CreateDIBSection(dc, &bi, DIB_RGB_COLORS, (void*)&bits, 0, 0); - if (bitmap == 0) - { - msg("error - CreateDIBSection failed"); - } - else - { - memset(bits, 0, width * height * 4); - dc1 = CreateCompatibleDC(dc); - SelectObject(dc1, bitmap); - if (!BitBlt(dc1, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY)) + } + + for (x1 = 32; x1 < 0x4e00; x1++) + { + check_messages(); + dc = GetWindowDC(g_wnd); + saved = SelectObject(dc, g_font); + + if (!GetCharABCWidths(dc, x1, x1, &abc)) { - show_last_error(); + show_last_error(); } - bmtext = (char*)g_malloc(width * height + 16, 1); - bmtextindex = 0; - for (index1 = (height - 1); index1 >= 0; index1--) + + text[0] = (TCHAR)x1; + text[1] = 0; + + if (!GetTextExtentPoint32(dc, text, 1, &sz)) { - for (index2 = 0; index2 < width; index2++) - { - pixel = ((int*)bits)[index1 * width + index2]; - red = (pixel >> 16) & 0xff; - green = (pixel >> 8) & 0xff; - blue = (pixel >> 0) & 0xff; - if (red == 0 && green == 0 && blue == 0) + show_last_error(); + } + + SelectObject(dc, saved); + ReleaseDC(g_wnd, dc); + + if ((sz.cx > 0) && (sz.cy > 0)) + { + dc = GetWindowDC(g_wnd); + saved = SelectObject(dc, g_font); + SetBkColor(dc, RGB(255, 255, 255)); + + if (!ExtTextOut(dc, 50, 50, ETO_OPAQUE, 0, text, 1, 0)) { - bmtext[bmtextindex] = '1'; - bmtextindex++; + show_last_error(); + } + + SelectObject(dc, saved); + ReleaseDC(g_wnd, dc); + Sleep(10); + /* width */ + x2 = abc.abcB; + g_file_write(fd, (char *)&x2, 2); + /* height */ + x2 = sz.cy; + g_file_write(fd, (char *)&x2, 2); + /* baseline */ + x2 = -sz.cy; + g_file_write(fd, (char *)&x2, 2); + /* offset */ + x2 = abc.abcA; + g_file_write(fd, (char *)&x2, 2); + /* incby */ + x2 = sz.cx; + g_file_write(fd, (char *)&x2, 2); + /* pad */ + index1 = 0; + + while (index1 < 6) + { + g_file_write(fd, &zero1, 1); + index1++; + } + + dc = GetWindowDC(g_wnd); + rect.left = 50 + abc.abcA; + rect.top = 50; + rect.right = rect.left + abc.abcB; + rect.bottom = rect.top + sz.cy; + memset(&bi, 0, sizeof(bi)); + width = (abc.abcB + 7) & (~7); + height = sz.cy; + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + bi.bmiHeader.biWidth = width; + bi.bmiHeader.biHeight = height; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bitmap = CreateDIBSection(dc, &bi, DIB_RGB_COLORS, (void *)&bits, 0, 0); + + if (bitmap == 0) + { + msg("error - CreateDIBSection failed"); } else { - bmtext[bmtextindex] = '0'; - bmtextindex++; + memset(bits, 0, width * height * 4); + dc1 = CreateCompatibleDC(dc); + SelectObject(dc1, bitmap); + + if (!BitBlt(dc1, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY)) + { + show_last_error(); + } + + bmtext = (char *)g_malloc(width * height + 16, 1); + bmtextindex = 0; + + for (index1 = (height - 1); index1 >= 0; index1--) + { + for (index2 = 0; index2 < width; index2++) + { + pixel = ((int *)bits)[index1 * width + index2]; + red = (pixel >> 16) & 0xff; + green = (pixel >> 8) & 0xff; + blue = (pixel >> 0) & 0xff; + + if (red == 0 && green == 0 && blue == 0) + { + bmtext[bmtextindex] = '1'; + bmtextindex++; + } + else + { + bmtext[bmtextindex] = '0'; + bmtextindex++; + } + } + } + + outlen = 0; + b1 = 0; + roller = 0; + len = g_strlen(bmtext); + + for (index2 = 0; index2 < len; index2++) + { + if (bmtext[index2] == '1') + { + switch (roller) + { + case 0: + b1 = b1 | 0x80; + break; + case 1: + b1 = b1 | 0x40; + break; + case 2: + b1 = b1 | 0x20; + break; + case 3: + b1 = b1 | 0x10; + break; + case 4: + b1 = b1 | 0x08; + break; + case 5: + b1 = b1 | 0x04; + break; + case 6: + b1 = b1 | 0x02; + break; + case 7: + b1 = b1 | 0x01; + break; + } + } + + roller++; + + if (roller == 8) + { + roller = 0; + g_file_write(fd, &b1, 1); + outlen++; + b1 = 0; + } + } + + while ((outlen % 4) != 0) + { + g_file_write(fd, &zero1, 1); + outlen++; + } + + free(bmtext); + DeleteDC(dc1); + DeleteObject(bitmap); } - } - } - outlen = 0; - b1 = 0; - roller = 0; - len = g_strlen(bmtext); - for (index2 = 0; index2 < len; index2++) - { - if (bmtext[index2] == '1') - { - switch (roller) + + if (sz.cx != (long)(abc.abcA + abc.abcB + abc.abcC)) { - case 0: b1 = b1 | 0x80; break; - case 1: b1 = b1 | 0x40; break; - case 2: b1 = b1 | 0x20; break; - case 3: b1 = b1 | 0x10; break; - case 4: b1 = b1 | 0x08; break; - case 5: b1 = b1 | 0x04; break; - case 6: b1 = b1 | 0x02; break; - case 7: b1 = b1 | 0x01; break; + msg("error - width not right 1"); } - } - roller++; - if (roller == 8) - { - roller = 0; - g_file_write(fd, &b1, 1); - outlen++; - b1 = 0; - } + + brush = CreateSolidBrush(RGB(255, 255, 255)); + FillRect(dc, &rect, brush); + DeleteObject(brush); + ReleaseDC(g_wnd, dc); } - while ((outlen % 4) != 0) + else { - g_file_write(fd, &zero1, 1); - outlen++; + /* write out a blank glyph here */ + /* width */ + x2 = 1; + g_file_write(fd, (char *)&x2, 2); + /* height */ + x2 = 1; + g_file_write(fd, (char *)&x2, 2); + /* baseline */ + x2 = 0; + g_file_write(fd, (char *)&x2, 2); + /* offset */ + x2 = 0; + g_file_write(fd, (char *)&x2, 2); + /* incby */ + x2 = 1; + g_file_write(fd, (char *)&x2, 2); + /* pad */ + index1 = 0; + + while (index1 < 6) + { + g_file_write(fd, &zero1, 1); + index1++; + } + + /* blank bitmap */ + index1 = 0; + + while (index1 < 4) + { + g_file_write(fd, &zero1, 1); + index1++; + } } - free(bmtext); - DeleteDC(dc1); - DeleteObject(bitmap); - } - if (sz.cx != (long)(abc.abcA + abc.abcB + abc.abcC)) - { - msg("error - width not right 1"); - } - brush = CreateSolidBrush(RGB(255, 255, 255)); - FillRect(dc, &rect, brush); - DeleteObject(brush); - ReleaseDC(g_wnd, dc); } - else - { - /* write out a blank glyph here */ - /* width */ - x2 = 1; - g_file_write(fd, (char*)&x2, 2); - /* height */ - x2 = 1; - g_file_write(fd, (char*)&x2, 2); - /* baseline */ - x2 = 0; - g_file_write(fd, (char*)&x2, 2); - /* offset */ - x2 = 0; - g_file_write(fd, (char*)&x2, 2); - /* incby */ - x2 = 1; - g_file_write(fd, (char*)&x2, 2); - /* pad */ - index1 = 0; - while (index1 < 6) - { - g_file_write(fd, &zero1, 1); - index1++; - } - /* blank bitmap */ - index1 = 0; - while (index1 < 4) - { - g_file_write(fd, &zero1, 1); - index1++; - } - } - } - g_file_close(fd); - msg("done"); - g_running = 0; - return 0; + + g_file_close(fd); + msg("done"); + g_running = 0; + return 0; } /*****************************************************************************/ static LRESULT CALLBACK wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - PAINTSTRUCT ps; - HBRUSH brush; - RECT rect; + PAINTSTRUCT ps; + HBRUSH brush; + RECT rect; - switch (message) - { - case WM_PAINT: - BeginPaint(hWnd, &ps); - brush = CreateSolidBrush(RGB(255, 255, 255)); - rect = ps.rcPaint; - FillRect(ps.hdc, &rect, brush); - DeleteObject(brush); - EndPaint(hWnd, &ps); - break; - case WM_CLOSE: - DestroyWindow(g_wnd); - g_wnd = 0; - break; - case WM_DESTROY: - PostQuitMessage(0); - break; - case WM_TIMER: - KillTimer(g_wnd, 1); - font_dump(); - break; - case WM_COMMAND: - if ((HWND)lParam == g_exit_button) - { - PostMessage(g_wnd, WM_CLOSE, 0, 0); - } - else if ((HWND)lParam == g_go_button) - { - while (SendMessage(g_lb, LB_GETCOUNT, 0, 0) > 0) - { - SendMessage(g_lb, LB_DELETESTRING, 0, 0); - } - SetTimer(g_wnd, 1, 1000, 0); - } - break; - } - return DefWindowProc(hWnd, message, wParam, lParam); + switch (message) + { + case WM_PAINT: + BeginPaint(hWnd, &ps); + brush = CreateSolidBrush(RGB(255, 255, 255)); + rect = ps.rcPaint; + FillRect(ps.hdc, &rect, brush); + DeleteObject(brush); + EndPaint(hWnd, &ps); + break; + case WM_CLOSE: + DestroyWindow(g_wnd); + g_wnd = 0; + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + case WM_TIMER: + KillTimer(g_wnd, 1); + font_dump(); + break; + case WM_COMMAND: + + if ((HWND)lParam == g_exit_button) + { + PostMessage(g_wnd, WM_CLOSE, 0, 0); + } + else if ((HWND)lParam == g_go_button) + { + while (SendMessage(g_lb, LB_GETCOUNT, 0, 0) > 0) + { + SendMessage(g_lb, LB_DELETESTRING, 0, 0); + } + + SetTimer(g_wnd, 1, 1000, 0); + } + + break; + } + + return DefWindowProc(hWnd, message, wParam, lParam); } /*****************************************************************************/ static int create_window(void) { - WNDCLASS wc; - DWORD style; - HDC dc; - int height; - int left; - int top; + WNDCLASS wc; + DWORD style; + HDC dc; + int height; + int left; + int top; - ZeroMemory(&wc, sizeof(wc)); - wc.lpfnWndProc = wnd_proc; /* points to window procedure */ - /* name of window class */ - wc.lpszClassName = _T("fontdump"); - wc.hCursor = LoadCursor(0, IDC_ARROW); - /* Register the window class. */ - if (!RegisterClass(&wc)) - { - return 0; /* Failed to register window class */ - } - style = WS_OVERLAPPED | WS_CAPTION | WS_POPUP | WS_MINIMIZEBOX | - WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX; - left = GetSystemMetrics(SM_CXSCREEN) / 2 - 640 / 2; - top = GetSystemMetrics(SM_CYSCREEN) / 2 - 480 / 2; - g_wnd = CreateWindow(wc.lpszClassName, _T("fontdump"), - style, left, top, 640, 480, - (HWND) NULL, (HMENU) NULL, g_instance, - (LPVOID) NULL); - style = WS_CHILD | WS_VISIBLE | WS_BORDER; - g_lb = CreateWindow(_T("LISTBOX"), _T("LISTBOX1"), style, - 200, 10, 400, 400, g_wnd, 0, g_instance, 0); - style = WS_CHILD | WS_VISIBLE; - g_exit_button = CreateWindow(_T("BUTTON"), _T("Exit"), style, - 540, 410, 75, 25, g_wnd, 0, g_instance, 0); - g_go_button = CreateWindow(_T("BUTTON"), _T("Go"), style, - 440, 410, 75, 25, g_wnd, 0, g_instance, 0); - style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN; - g_font_list = CreateWindow(_T("COMBOBOX"), _T("COMBOBOX1"), style, - 50, 250, 125, 125, g_wnd, 0, g_instance, 0); - ShowWindow(g_wnd, SW_SHOWNORMAL); - PostMessage(g_wnd, WM_SETFONT, (WPARAM)g_font, 0); - SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Tahoma"); - SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"DejaVu Serif"); - SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"DejaVu Sans"); - SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Arial"); - SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Comic Sans MS"); - return 0; + ZeroMemory(&wc, sizeof(wc)); + wc.lpfnWndProc = wnd_proc; /* points to window procedure */ + /* name of window class */ + wc.lpszClassName = _T("fontdump"); + wc.hCursor = LoadCursor(0, IDC_ARROW); + + /* Register the window class. */ + if (!RegisterClass(&wc)) + { + return 0; /* Failed to register window class */ + } + + style = WS_OVERLAPPED | WS_CAPTION | WS_POPUP | WS_MINIMIZEBOX | + WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX; + left = GetSystemMetrics(SM_CXSCREEN) / 2 - 640 / 2; + top = GetSystemMetrics(SM_CYSCREEN) / 2 - 480 / 2; + g_wnd = CreateWindow(wc.lpszClassName, _T("fontdump"), + style, left, top, 640, 480, + (HWND) NULL, (HMENU) NULL, g_instance, + (LPVOID) NULL); + style = WS_CHILD | WS_VISIBLE | WS_BORDER; + g_lb = CreateWindow(_T("LISTBOX"), _T("LISTBOX1"), style, + 200, 10, 400, 400, g_wnd, 0, g_instance, 0); + style = WS_CHILD | WS_VISIBLE; + g_exit_button = CreateWindow(_T("BUTTON"), _T("Exit"), style, + 540, 410, 75, 25, g_wnd, 0, g_instance, 0); + g_go_button = CreateWindow(_T("BUTTON"), _T("Go"), style, + 440, 410, 75, 25, g_wnd, 0, g_instance, 0); + style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN; + g_font_list = CreateWindow(_T("COMBOBOX"), _T("COMBOBOX1"), style, + 50, 250, 125, 125, g_wnd, 0, g_instance, 0); + ShowWindow(g_wnd, SW_SHOWNORMAL); + PostMessage(g_wnd, WM_SETFONT, (WPARAM)g_font, 0); + SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Tahoma"); + SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"DejaVu Serif"); + SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"DejaVu Sans"); + SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Arial"); + SendMessageA(g_font_list, CB_ADDSTRING, 0, (LPARAM)"Comic Sans MS"); + return 0; } /*****************************************************************************/ static int main_loop(void) { - MSG msg; + MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return (int)(msg.wParam); + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (int)(msg.wParam); } /*****************************************************************************/ @@ -452,7 +528,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { - g_instance = hInstance; - create_window(); - return main_loop(); + g_instance = hInstance; + create_window(); + return main_loop(); } diff --git a/freerdp/xrdp-color.c b/freerdp/xrdp-color.c index 1bbdef43..0ecf4dbf 100644 --- a/freerdp/xrdp-color.c +++ b/freerdp/xrdp-color.c @@ -1,279 +1,314 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2010 - - freerdp wrapper - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * freerdp wrapper + */ #include "xrdp-freerdp.h" -char* APP_CC -convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, - int width, int height, int* palette) +char *APP_CC +convert_bitmap(int in_bpp, int out_bpp, char *bmpdata, + int width, int height, int *palette) { - char* out; - char* src; - char* dst; - int i; - int j; - int red; - int green; - int blue; - int pixel; + char *out; + char *src; + char *dst; + int i; + int j; + int red; + int green; + int blue; + int pixel; - if ((in_bpp == 8) && (out_bpp == 8)) - { - out = (char*)g_malloc(width * height, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + if ((in_bpp == 8) && (out_bpp == 8)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - *dst = pixel; - src++; - dst++; - } + out = (char *)g_malloc(width * height, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + *dst = pixel; + src++; + dst++; + } + } + + return out; } - return out; - } - if ((in_bpp == 8) && (out_bpp == 16)) - { - out = (char*)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 8) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16*)dst) = pixel; - src++; - dst += 2; - } + out = (char *)g_malloc(width * height * 2, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *((tui16 *)dst) = pixel; + src++; + dst += 2; + } + } + + return out; } - return out; - } - if ((in_bpp == 8) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 8) && (out_bpp == 24)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src++; - dst += 4; - } + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src++; + dst += 4; + } + } + + return out; } - return out; - } - if ((in_bpp == 15) && (out_bpp == 16)) - { - out = (char*)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 15) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16*)dst) = pixel; - src += 2; - dst += 2; - } + out = (char *)g_malloc(width * height * 2, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *((tui16 *)dst) = pixel; + src += 2; + dst += 2; + } + } + + return out; } - return out; - } - if ((in_bpp == 15) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 15) && (out_bpp == 24)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src += 2; - dst += 4; - } + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src += 2; + dst += 4; + } + } + + return out; } - return out; - } - if ((in_bpp == 16) && (out_bpp == 16)) - { - return bmpdata; - } - if ((in_bpp == 16) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 16) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src += 2; - dst += 4; - } + return bmpdata; } - return out; - } - if ((in_bpp == 24) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 16) && (out_bpp == 24)) { - for (j = 0; j < width; j++) - { - blue = *((tui8*)src); - src++; - green = *((tui8*)src); - src++; - red = *((tui8*)src); - src++; - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - dst += 4; - } + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR16(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src += 2; + dst += 4; + } + } + + return out; } - return out; - } - if ((in_bpp == 32) && (out_bpp == 24)) - { - return bmpdata; - } - if ((in_bpp == 32) && (out_bpp == 32)) - { - return bmpdata; - } - if ((in_bpp == 15) && (out_bpp == 15)) - { - return bmpdata; - } - g_writeln("convert_bitmap: error unknown conversion from %d to %d", - in_bpp, out_bpp); - return 0; + + if ((in_bpp == 24) && (out_bpp == 24)) + { + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + blue = *((tui8 *)src); + src++; + green = *((tui8 *)src); + src++; + red = *((tui8 *)src); + src++; + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + dst += 4; + } + } + + return out; + } + + if ((in_bpp == 32) && (out_bpp == 24)) + { + return bmpdata; + } + + if ((in_bpp == 32) && (out_bpp == 32)) + { + return bmpdata; + } + + if ((in_bpp == 15) && (out_bpp == 15)) + { + return bmpdata; + } + + g_writeln("convert_bitmap: error unknown conversion from %d to %d", + in_bpp, out_bpp); + return 0; } /*****************************************************************************/ /* returns color or 0 */ int APP_CC -convert_color(int in_bpp, int out_bpp, int in_color, int* palette) +convert_color(int in_bpp, int out_bpp, int in_color, int *palette) { - int pixel; - int red; - int green; - int blue; + int pixel; + int red; + int green; + int blue; - if ((in_bpp == 1) && (out_bpp == 24)) - { - pixel = in_color == 0 ? 0 : 0xffffff; - return pixel; - } - if ((in_bpp == 8) && (out_bpp == 8)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - return pixel; - } - if ((in_bpp == 8) && (out_bpp == 16)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - if ((in_bpp == 8) && (out_bpp == 24)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 15) && (out_bpp == 16)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - if ((in_bpp == 15) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 16) && (out_bpp == 16)) - { - return in_color; - } - if ((in_bpp == 16) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 24) && (out_bpp == 24)) - { - return in_color; - } - if ((in_bpp == 32) && (out_bpp == 24)) - { - return in_color; - } - if ((in_bpp == 32) && (out_bpp == 32)) - { - return in_color; - } - if ((in_bpp == 15) && (out_bpp == 15)) - { - return in_color; - } - g_writeln("convert_color: error unknown conversion from %d to %d", - in_bpp, out_bpp); - return 0; + if ((in_bpp == 1) && (out_bpp == 24)) + { + pixel = in_color == 0 ? 0 : 0xffffff; + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 8)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 16)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 24)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 16)) + { + pixel = in_color; + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 24)) + { + pixel = in_color; + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 16) && (out_bpp == 16)) + { + return in_color; + } + + if ((in_bpp == 16) && (out_bpp == 24)) + { + pixel = in_color; + SPLITCOLOR16(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 24) && (out_bpp == 24)) + { + return in_color; + } + + if ((in_bpp == 32) && (out_bpp == 24)) + { + return in_color; + } + + if ((in_bpp == 32) && (out_bpp == 32)) + { + return in_color; + } + + if ((in_bpp == 15) && (out_bpp == 15)) + { + return in_color; + } + + g_writeln("convert_color: error unknown conversion from %d to %d", + in_bpp, out_bpp); + return 0; } diff --git a/freerdp/xrdp-color.h b/freerdp/xrdp-color.h index c9375b53..3c58c032 100644 --- a/freerdp/xrdp-color.h +++ b/freerdp/xrdp-color.h @@ -1,22 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2010 - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef __XRDP_COLOR_H #define __XRDP_COLOR_H diff --git a/freerdp/xrdp-freerdp.c b/freerdp/xrdp-freerdp.c index f7e7fd5e..5ee58800 100644 --- a/freerdp/xrdp-freerdp.c +++ b/freerdp/xrdp-freerdp.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2010 - - freerdp wrapper - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * freerdp wrapper + */ #include "xrdp-freerdp.h" #include "xrdp-color.h" @@ -28,723 +26,744 @@ struct my_bitmap { - char* data; - int width; - int height; - int bpp; + char *data; + int width; + int height; + int bpp; }; struct my_cursor { - char* andmask; - int andbpp; - char* xormask; - int xorbpp; - int width; - int height; - int hotx; - int hoty; + char *andmask; + int andbpp; + char *xormask; + int xorbpp; + int width; + int height; + int hotx; + int hoty; }; /*****************************************************************************/ /* return error */ static int DEFAULT_CC -lib_mod_start(struct mod* mod, int w, int h, int bpp) +lib_mod_start(struct mod *mod, int w, int h, int bpp) { - LIB_DEBUG(mod, "in lib_mod_start"); - g_writeln("lib_mod_start: w %d h %d bpp %d", w, h, bpp); - mod->width = w; - mod->height = h; - mod->bpp = bpp; - if (bpp == 24) - { - mod->settings->server_depth = 32; - } - else - { - mod->settings->server_depth = mod->bpp; - } - mod->settings->width = mod->width; - mod->settings->height = mod->height; - LIB_DEBUG(mod, "out lib_mod_start"); - return 0; + LIB_DEBUG(mod, "in lib_mod_start"); + g_writeln("lib_mod_start: w %d h %d bpp %d", w, h, bpp); + mod->width = w; + mod->height = h; + mod->bpp = bpp; + + if (bpp == 24) + { + mod->settings->server_depth = 32; + } + else + { + mod->settings->server_depth = mod->bpp; + } + + mod->settings->width = mod->width; + mod->settings->height = mod->height; + LIB_DEBUG(mod, "out lib_mod_start"); + return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC -lib_mod_connect(struct mod* mod) +lib_mod_connect(struct mod *mod) { - int code; + int code; - LIB_DEBUG(mod, "in lib_mod_connect"); - code = mod->inst->rdp_connect(mod->inst); - g_writeln("lib_mod_connect: code %d", code); - LIB_DEBUG(mod, "out lib_mod_connect"); - return code; + LIB_DEBUG(mod, "in lib_mod_connect"); + code = mod->inst->rdp_connect(mod->inst); + g_writeln("lib_mod_connect: code %d", code); + LIB_DEBUG(mod, "out lib_mod_connect"); + return code; } /******************************************************************************/ /* return error */ static int DEFAULT_CC -lib_mod_event(struct mod* mod, int msg, long param1, long param2, +lib_mod_event(struct mod *mod, int msg, long param1, long param2, long param3, long param4) { - LIB_DEBUG(mod, "in lib_mod_event"); - int ext; + LIB_DEBUG(mod, "in lib_mod_event"); + int ext; - //g_writeln("%d %d %d %d %d", msg, param1, param2, param3, param4); - switch (msg) - { - case 15: - ext = param4 & 0x100 ? 1 : 0; - mod->inst->rdp_send_input_scancode(mod->inst, 0, ext, param3); - break; - case 16: - ext = param4 & 0x100 ? 1 : 0; - mod->inst->rdp_send_input_scancode(mod->inst, 1, ext, param3); - break; - case 17: - mod->inst->rdp_sync_input(mod->inst, param4); - break; - case 100: - mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_MOVE, - param1, param2); - break; - case 101: - mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON1, - param1, param2); - break; - case 102: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON1 | PTRFLAGS_DOWN, - param1, param2); - break; - case 103: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON2, param1, param2); - break; - case 104: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON2 | PTRFLAGS_DOWN, - param1, param2); - break; - case 105: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON3, param1, param2); - break; - case 106: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_BUTTON3 | PTRFLAGS_DOWN, - param1, param2); - break; - case 107: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_WHEEL | 0x0078, 0, 0); - break; - case 108: - break; - case 109: - mod->inst->rdp_send_input_mouse(mod->inst, - PTRFLAGS_WHEEL | - PTRFLAGS_WHEEL_NEGATIVE | 0x0088, 0, 0); - break; - case 110: - break; - } - LIB_DEBUG(mod, "out lib_mod_event"); - return 0; + //g_writeln("%d %d %d %d %d", msg, param1, param2, param3, param4); + switch (msg) + { + case 15: + ext = param4 & 0x100 ? 1 : 0; + mod->inst->rdp_send_input_scancode(mod->inst, 0, ext, param3); + break; + case 16: + ext = param4 & 0x100 ? 1 : 0; + mod->inst->rdp_send_input_scancode(mod->inst, 1, ext, param3); + break; + case 17: + mod->inst->rdp_sync_input(mod->inst, param4); + break; + case 100: + mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_MOVE, + param1, param2); + break; + case 101: + mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON1, + param1, param2); + break; + case 102: + mod->inst->rdp_send_input_mouse(mod->inst, + PTRFLAGS_BUTTON1 | PTRFLAGS_DOWN, + param1, param2); + break; + case 103: + mod->inst->rdp_send_input_mouse(mod->inst, + PTRFLAGS_BUTTON2, param1, param2); + break; + case 104: + mod->inst->rdp_send_input_mouse(mod->inst, + PTRFLAGS_BUTTON2 | PTRFLAGS_DOWN, + param1, param2); + break; + case 105: + mod->inst->rdp_send_input_mouse(mod->inst, + PTRFLAGS_BUTTON3, param1, param2); + break; + case 106: + mod->inst->rdp_send_input_mouse(mod->inst, + PTRFLAGS_BUTTON3 | PTRFLAGS_DOWN, + param1, param2); + break; + case 107: + mod->inst->rdp_send_input_mouse(mod->inst, + PTRFLAGS_WHEEL | 0x0078, 0, 0); + break; + case 108: + break; + case 109: + mod->inst->rdp_send_input_mouse(mod->inst, + PTRFLAGS_WHEEL | + PTRFLAGS_WHEEL_NEGATIVE | 0x0088, 0, 0); + break; + case 110: + break; + } + + LIB_DEBUG(mod, "out lib_mod_event"); + return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC -lib_mod_signal(struct mod* mod) +lib_mod_signal(struct mod *mod) { - LIB_DEBUG(mod, "in lib_mod_signal"); - g_writeln("lib_mod_signal:"); - LIB_DEBUG(mod, "out lib_mod_signal"); - return 0; + LIB_DEBUG(mod, "in lib_mod_signal"); + g_writeln("lib_mod_signal:"); + LIB_DEBUG(mod, "out lib_mod_signal"); + return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC -lib_mod_end(struct mod* mod) +lib_mod_end(struct mod *mod) { - g_writeln("lib_mod_end:"); - return 0; + g_writeln("lib_mod_end:"); + return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC -lib_mod_set_param(struct mod* mod, char* name, char* value) +lib_mod_set_param(struct mod *mod, char *name, char *value) { - g_writeln("lib_mod_set_param: name [%s] value [%s]", name, value); - if (g_strcmp(name, "hostname") == 0) - { - g_strncpy(mod->settings->hostname, value, sizeof(mod->settings->hostname)); - } - else if (g_strcmp(name, "ip") == 0) - { - g_strncpy(mod->settings->server, value, sizeof(mod->settings->server)); - } - else if (g_strcmp(name, "port") == 0) - { - mod->settings->tcp_port_rdp = g_atoi(value); - } - else if (g_strcmp(name, "keylayout") == 0) - { - mod->settings->keyboard_layout = g_atoi(value); - } - else if (g_strcmp(name, "name") == 0) - { - } - else if (g_strcmp(name, "lib") == 0) - { - } - else - { - g_writeln("lib_mod_set_param: unknown name [%s] value [%s]", name, value); - } - return 0; + g_writeln("lib_mod_set_param: name [%s] value [%s]", name, value); + + if (g_strcmp(name, "hostname") == 0) + { + g_strncpy(mod->settings->hostname, value, sizeof(mod->settings->hostname)); + } + else if (g_strcmp(name, "ip") == 0) + { + g_strncpy(mod->settings->server, value, sizeof(mod->settings->server)); + } + else if (g_strcmp(name, "port") == 0) + { + mod->settings->tcp_port_rdp = g_atoi(value); + } + else if (g_strcmp(name, "keylayout") == 0) + { + mod->settings->keyboard_layout = g_atoi(value); + } + else if (g_strcmp(name, "name") == 0) + { + } + else if (g_strcmp(name, "lib") == 0) + { + } + else + { + g_writeln("lib_mod_set_param: unknown name [%s] value [%s]", name, value); + } + + return 0; } /******************************************************************************/ static int DEFAULT_CC -mod_session_change(struct mod* v, int a, int b) +mod_session_change(struct mod *v, int a, int b) { - g_writeln("mod_session_change:"); - return 0; + g_writeln("mod_session_change:"); + return 0; } /******************************************************************************/ static int DEFAULT_CC -mod_get_wait_objs(struct mod* v, tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout) +mod_get_wait_objs(struct mod *v, tbus *read_objs, int *rcount, + tbus *write_objs, int *wcount, int *timeout) { - void** rfds; - void** wfds; + void **rfds; + void **wfds; - rfds = (void**)read_objs; - wfds = (void**)write_objs; - return v->inst->rdp_get_fds(v->inst, rfds, rcount, wfds, wcount); + rfds = (void **)read_objs; + wfds = (void **)write_objs; + return v->inst->rdp_get_fds(v->inst, rfds, rcount, wfds, wcount); } /******************************************************************************/ static int DEFAULT_CC -mod_check_wait_objs(struct mod* v) +mod_check_wait_objs(struct mod *v) { - return v->inst->rdp_check_fds(v->inst); + return v->inst->rdp_check_fds(v->inst); } /******************************************************************************/ static void DEFAULT_CC -ui_error(rdpInst* inst, const char* text) +ui_error(rdpInst *inst, const char *text) { - g_writeln("ui_error: %s", text); + g_writeln("ui_error: %s", text); } /******************************************************************************/ static void DEFAULT_CC -ui_warning(rdpInst* inst, const char* text) +ui_warning(rdpInst *inst, const char *text) { - g_writeln("ui_warning: %s", text); + g_writeln("ui_warning: %s", text); } /******************************************************************************/ static void DEFAULT_CC -ui_unimpl(rdpInst* inst, const char* text) +ui_unimpl(rdpInst *inst, const char *text) { - g_writeln("ui_unimpl: %s", text); + g_writeln("ui_unimpl: %s", text); } /******************************************************************************/ static void DEFAULT_CC -ui_begin_update(rdpInst* inst) +ui_begin_update(rdpInst *inst) { - struct mod* mod; + struct mod *mod; - mod = GET_MOD(inst); - mod->server_begin_update(mod); + mod = GET_MOD(inst); + mod->server_begin_update(mod); } /******************************************************************************/ static void DEFAULT_CC -ui_end_update(rdpInst* inst) +ui_end_update(rdpInst *inst) { - struct mod* mod; + struct mod *mod; - mod = GET_MOD(inst); - mod->server_end_update(mod); + mod = GET_MOD(inst); + mod->server_end_update(mod); } /******************************************************************************/ static void DEFAULT_CC -ui_desktop_save(rdpInst* inst, int offset, int x, int y, +ui_desktop_save(rdpInst *inst, int offset, int x, int y, int cx, int cy) { - g_writeln("ui_desktop_save:"); + g_writeln("ui_desktop_save:"); } /******************************************************************************/ static void DEFAULT_CC -ui_desktop_restore(rdpInst* inst, int offset, int x, int y, - int cx, int cy) +ui_desktop_restore(rdpInst *inst, int offset, int x, int y, + int cx, int cy) { - g_writeln("ui_desktop_restore:"); + g_writeln("ui_desktop_restore:"); } /******************************************************************************/ static RD_HBITMAP DEFAULT_CC -ui_create_bitmap(rdpInst* inst, int width, int height, uint8* data) +ui_create_bitmap(rdpInst *inst, int width, int height, uint8 *data) { - struct my_bitmap* bm; - struct mod* mod; - int size; - int bpp; - char* bmpdata; + struct my_bitmap *bm; + struct mod *mod; + int size; + int bpp; + char *bmpdata; - mod = GET_MOD(inst); - bpp = mod->bpp == 24 ? 32 : mod->bpp; - bm = (struct my_bitmap*)g_malloc(sizeof(struct my_bitmap), 1); - bm->width = width; - bm->height = height; - bm->bpp = bpp; - bmpdata = convert_bitmap(mod->settings->server_depth, bpp, - data, width, height, mod->cmap); - if (bmpdata == (char*)data) - { - size = width * height * ((bpp + 7) / 8); - bm->data = (char*)g_malloc(size, 0); - g_memcpy(bm->data, bmpdata, size); - } - else - { - bm->data = bmpdata; - } - return bm; + mod = GET_MOD(inst); + bpp = mod->bpp == 24 ? 32 : mod->bpp; + bm = (struct my_bitmap *)g_malloc(sizeof(struct my_bitmap), 1); + bm->width = width; + bm->height = height; + bm->bpp = bpp; + bmpdata = convert_bitmap(mod->settings->server_depth, bpp, + data, width, height, mod->cmap); + + if (bmpdata == (char *)data) + { + size = width * height * ((bpp + 7) / 8); + bm->data = (char *)g_malloc(size, 0); + g_memcpy(bm->data, bmpdata, size); + } + else + { + bm->data = bmpdata; + } + + return bm; } /******************************************************************************/ static void DEFAULT_CC -ui_paint_bitmap(rdpInst* inst, int x, int y, int cx, int cy, int width, - int height, uint8* data) +ui_paint_bitmap(rdpInst *inst, int x, int y, int cx, int cy, int width, + int height, uint8 *data) { - struct mod* mod; - char* bmpdata; + struct mod *mod; + char *bmpdata; - mod = GET_MOD(inst); - bmpdata = convert_bitmap(mod->settings->server_depth, mod->bpp, - data, width, height, mod->cmap); - if (bmpdata != 0) - { - mod->server_paint_rect(mod, x, y, cx, cy, bmpdata, width, height, 0, 0); - } - if (bmpdata != (char*)data) - { - g_free(bmpdata); - } + mod = GET_MOD(inst); + bmpdata = convert_bitmap(mod->settings->server_depth, mod->bpp, + data, width, height, mod->cmap); + + if (bmpdata != 0) + { + mod->server_paint_rect(mod, x, y, cx, cy, bmpdata, width, height, 0, 0); + } + + if (bmpdata != (char *)data) + { + g_free(bmpdata); + } } /******************************************************************************/ static void DEFAULT_CC -ui_destroy_bitmap(rdpInst* inst, RD_HBITMAP bmp) +ui_destroy_bitmap(rdpInst *inst, RD_HBITMAP bmp) { - struct my_bitmap* bm; + struct my_bitmap *bm; - bm = (struct my_bitmap*)bmp; - g_free(bm->data); - g_free(bm); + bm = (struct my_bitmap *)bmp; + g_free(bm->data); + g_free(bm); } /******************************************************************************/ static void DEFAULT_CC -ui_line(rdpInst* inst, uint8 opcode, int startx, int starty, int endx, - int endy, RD_PEN* pen) +ui_line(rdpInst *inst, uint8 opcode, int startx, int starty, int endx, + int endy, RD_PEN *pen) { - g_writeln("ui_line:"); + g_writeln("ui_line:"); } /******************************************************************************/ static void DEFAULT_CC -ui_rect(rdpInst* inst, int x, int y, int cx, int cy, uint32 color) +ui_rect(rdpInst *inst, int x, int y, int cx, int cy, uint32 color) { - struct mod* mod; + struct mod *mod; - mod = GET_MOD(inst); - color = convert_color(mod->settings->server_depth, mod->bpp, - color, mod->cmap); - mod->server_set_fgcolor(mod, color); - mod->server_fill_rect(mod, x, y, cx, cy); + mod = GET_MOD(inst); + color = convert_color(mod->settings->server_depth, mod->bpp, + color, mod->cmap); + mod->server_set_fgcolor(mod, color); + mod->server_fill_rect(mod, x, y, cx, cy); } /******************************************************************************/ static void DEFAULT_CC -ui_polygon(rdpInst* inst, uint8 opcode, uint8 fillmode, RD_POINT* point, - int npoints, RD_BRUSH* brush, uint32 bgcolor, uint32 fgcolor) +ui_polygon(rdpInst *inst, uint8 opcode, uint8 fillmode, RD_POINT *point, + int npoints, RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor) { - g_writeln("ui_polygon:"); + g_writeln("ui_polygon:"); } /******************************************************************************/ static void DEFAULT_CC -ui_polyline(rdpInst* inst, uint8 opcode, RD_POINT* points, int npoints, - RD_PEN* pen) +ui_polyline(rdpInst *inst, uint8 opcode, RD_POINT *points, int npoints, + RD_PEN *pen) { - g_writeln("ui_polyline:"); + g_writeln("ui_polyline:"); } /******************************************************************************/ static void DEFAULT_CC -ui_ellipse(rdpInst* inst, uint8 opcode, uint8 fillmode, int x, int y, - int cx, int cy, RD_BRUSH* brush, uint32 bgcolor, uint32 fgcolor) +ui_ellipse(rdpInst *inst, uint8 opcode, uint8 fillmode, int x, int y, + int cx, int cy, RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor) { - g_writeln("ui_ellipse:"); + g_writeln("ui_ellipse:"); } /******************************************************************************/ static void DEFAULT_CC -ui_add_char(rdpInst * inst, uint8 font, uint16 character, sint16 offset, - sint16 baseline, uint16 width, uint16 height, uint8 * data) +ui_add_char(rdpInst *inst, uint8 font, uint16 character, sint16 offset, + sint16 baseline, uint16 width, uint16 height, uint8 *data) { - struct mod* mod; + struct mod *mod; - //g_writeln("ui_add_char:"); - mod = GET_MOD(inst); - mod->server_add_char(mod, font, character, offset, baseline, - width, height, (char*)data); + //g_writeln("ui_add_char:"); + mod = GET_MOD(inst); + mod->server_add_char(mod, font, character, offset, baseline, + width, height, (char *)data); } /******************************************************************************/ static void DEFAULT_CC -ui_draw_text(rdpInst* inst, uint8 font, uint8 flags, +ui_draw_text(rdpInst *inst, 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, RD_BRUSH * brush, - uint32 bgcolor, uint32 fgcolor, uint8 * text, uint8 length) + int boxx, int boxy, int boxcx, int boxcy, RD_BRUSH *brush, + uint32 bgcolor, uint32 fgcolor, uint8 *text, uint8 length) { - struct mod* mod; + struct mod *mod; - //g_writeln("ui_draw_text: flags %d mixmode %d x %d y %d", flags, mixmode, x, y); - //g_writeln("%d %d %d %d %d %d %d %d", clipx, clipy, clipcx, clipcy, boxx, boxy, boxcx, boxcy); - mod = GET_MOD(inst); - fgcolor = convert_color(mod->settings->server_depth, mod->bpp, - fgcolor, mod->cmap); - mod->server_set_fgcolor(mod, fgcolor); - bgcolor = convert_color(mod->settings->server_depth, mod->bpp, - bgcolor, mod->cmap); - mod->server_set_bgcolor(mod, bgcolor); - mod->server_draw_text(mod, font, flags, mixmode, - clipx, clipy, clipx + clipcx, clipy + clipcy, - boxx, boxy, boxx + boxcx, boxy + boxcy, x, y, - (char*)text, length); + //g_writeln("ui_draw_text: flags %d mixmode %d x %d y %d", flags, mixmode, x, y); + //g_writeln("%d %d %d %d %d %d %d %d", clipx, clipy, clipcx, clipcy, boxx, boxy, boxcx, boxcy); + mod = GET_MOD(inst); + fgcolor = convert_color(mod->settings->server_depth, mod->bpp, + fgcolor, mod->cmap); + mod->server_set_fgcolor(mod, fgcolor); + bgcolor = convert_color(mod->settings->server_depth, mod->bpp, + bgcolor, mod->cmap); + mod->server_set_bgcolor(mod, bgcolor); + mod->server_draw_text(mod, font, flags, mixmode, + clipx, clipy, clipx + clipcx, clipy + clipcy, + boxx, boxy, boxx + boxcx, boxy + boxcy, x, y, + (char *)text, length); } /******************************************************************************/ static void DEFAULT_CC -ui_start_draw_glyphs(rdpInst* inst, uint32 bgcolor, uint32 fgcolor) +ui_start_draw_glyphs(rdpInst *inst, uint32 bgcolor, uint32 fgcolor) { - g_writeln("ui_start_draw_glyphs:"); + g_writeln("ui_start_draw_glyphs:"); } /******************************************************************************/ static void DEFAULT_CC -ui_draw_glyph(rdpInst* inst, int x, int y, int cx, int cy, - RD_HGLYPH glyph) +ui_draw_glyph(rdpInst *inst, int x, int y, int cx, int cy, + RD_HGLYPH glyph) { - g_writeln("ui_draw_glyph:"); + g_writeln("ui_draw_glyph:"); } /******************************************************************************/ static void DEFAULT_CC -ui_end_draw_glyphs(rdpInst* inst, int x, int y, int cx, int cy) +ui_end_draw_glyphs(rdpInst *inst, int x, int y, int cx, int cy) { - g_writeln("ui_end_draw_glyphs:"); + g_writeln("ui_end_draw_glyphs:"); } /******************************************************************************/ static uint32 DEFAULT_CC -ui_get_toggle_keys_state(rdpInst* inst) +ui_get_toggle_keys_state(rdpInst *inst) { - g_writeln("ui_get_toggle_keys_state:"); - return 0; + g_writeln("ui_get_toggle_keys_state:"); + return 0; } /******************************************************************************/ static void DEFAULT_CC -ui_bell(rdpInst* inst) +ui_bell(rdpInst *inst) { - g_writeln("ui_bell:"); + g_writeln("ui_bell:"); } /******************************************************************************/ static void DEFAULT_CC -ui_destblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy) +ui_destblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy) { - struct mod* mod; + struct mod *mod; - g_writeln("ui_destblt:"); - mod = GET_MOD(inst); - mod->server_set_opcode(mod, opcode); - mod->server_fill_rect(mod, x, y, cx, cy); - mod->server_set_opcode(mod, 0xcc); + g_writeln("ui_destblt:"); + mod = GET_MOD(inst); + mod->server_set_opcode(mod, opcode); + mod->server_fill_rect(mod, x, y, cx, cy); + mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC -ui_patblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy, - RD_BRUSH* brush, uint32 bgcolor, uint32 fgcolor) +ui_patblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy, + RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor) { - struct mod* mod; - uint8 idata[8]; - int index; + struct mod *mod; + uint8 idata[8]; + int index; - mod = GET_MOD(inst); - mod->server_set_opcode(mod, opcode); - fgcolor = convert_color(mod->settings->server_depth, mod->bpp, - fgcolor, mod->cmap); - mod->server_set_fgcolor(mod, fgcolor); - bgcolor = convert_color(mod->settings->server_depth, mod->bpp, - bgcolor, mod->cmap); - mod->server_set_bgcolor(mod, bgcolor); - mod->server_set_mixmode(mod, 1); - if (brush->bd != 0) - { - if (brush->bd->color_code == 1) /* 8x8 1 bpp */ + mod = GET_MOD(inst); + mod->server_set_opcode(mod, opcode); + fgcolor = convert_color(mod->settings->server_depth, mod->bpp, + fgcolor, mod->cmap); + mod->server_set_fgcolor(mod, fgcolor); + bgcolor = convert_color(mod->settings->server_depth, mod->bpp, + bgcolor, mod->cmap); + mod->server_set_bgcolor(mod, bgcolor); + mod->server_set_mixmode(mod, 1); + + if (brush->bd != 0) { - for (index = 0; index < 8; index++) - { - idata[index] = ~(brush->bd->data[index]); - } - mod->server_set_brush(mod, brush->xorigin, brush->yorigin, - brush->style, idata); + if (brush->bd->color_code == 1) /* 8x8 1 bpp */ + { + for (index = 0; index < 8; index++) + { + idata[index] = ~(brush->bd->data[index]); + } + + mod->server_set_brush(mod, brush->xorigin, brush->yorigin, + brush->style, idata); + } + else + { + g_writeln("ui_patblt: error color_code %d", brush->bd->color_code); + } } else { - g_writeln("ui_patblt: error color_code %d", brush->bd->color_code); + for (index = 0; index < 8; index++) + { + idata[index] = ~(brush->pattern[index]); + } + + mod->server_set_brush(mod, brush->xorigin, brush->yorigin, + brush->style, idata); } - } - else - { - for (index = 0; index < 8; index++) - { - idata[index] = ~(brush->pattern[index]); - } - mod->server_set_brush(mod, brush->xorigin, brush->yorigin, - brush->style, idata); - } - mod->server_fill_rect(mod, x, y, cx, cy); - mod->server_set_opcode(mod, 0xcc); - mod->server_set_mixmode(mod, 0); + + mod->server_fill_rect(mod, x, y, cx, cy); + mod->server_set_opcode(mod, 0xcc); + mod->server_set_mixmode(mod, 0); } /******************************************************************************/ static void DEFAULT_CC -ui_screenblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy, +ui_screenblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy) { - struct mod* mod; + struct mod *mod; - mod = GET_MOD(inst); - mod->server_set_opcode(mod, opcode); - mod->server_screen_blt(mod, x, y, cx, cy, srcx, srcy); - mod->server_set_opcode(mod, 0xcc); + mod = GET_MOD(inst); + mod->server_set_opcode(mod, opcode); + mod->server_screen_blt(mod, x, y, cx, cy, srcx, srcy); + mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC -ui_memblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy, +ui_memblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy, RD_HBITMAP src, int srcx, int srcy) { - struct my_bitmap* bitmap; - struct mod* mod; - char* bmpdata; + struct my_bitmap *bitmap; + struct mod *mod; + char *bmpdata; - mod = GET_MOD(inst); - bitmap = (struct my_bitmap*)src; - mod->server_set_opcode(mod, opcode); - mod->server_paint_rect(mod, x, y, cx, cy, bitmap->data, - bitmap->width, bitmap->height, srcx, srcy); - mod->server_set_opcode(mod, 0xcc); + mod = GET_MOD(inst); + bitmap = (struct my_bitmap *)src; + mod->server_set_opcode(mod, opcode); + mod->server_paint_rect(mod, x, y, cx, cy, bitmap->data, + bitmap->width, bitmap->height, srcx, srcy); + mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC -ui_triblt(rdpInst* inst, uint8 opcode, int x, int y, int cx, int cy, - RD_HBITMAP src, int srcx, int srcy, RD_BRUSH* brush, +ui_triblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy, + RD_HBITMAP src, int srcx, int srcy, RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor) { - g_writeln("ui_triblt:"); + g_writeln("ui_triblt:"); } /******************************************************************************/ static RD_HGLYPH DEFAULT_CC -ui_create_glyph(rdpInst* inst, int width, int height, uint8* data) +ui_create_glyph(rdpInst *inst, int width, int height, uint8 *data) { - g_writeln("ui_create_glyph:"); - return 0; + g_writeln("ui_create_glyph:"); + return 0; } /******************************************************************************/ static void DEFAULT_CC -ui_destroy_glyph(rdpInst* inst, RD_HGLYPH glyph) +ui_destroy_glyph(rdpInst *inst, RD_HGLYPH glyph) { - g_writeln("ui_destroy_glyph:"); + g_writeln("ui_destroy_glyph:"); } /******************************************************************************/ static int DEFAULT_CC -ui_select(rdpInst* inst, int rdp_socket) +ui_select(rdpInst *inst, int rdp_socket) { - return 1; + return 1; } /******************************************************************************/ static void DEFAULT_CC -ui_set_clip(rdpInst* inst, int x, int y, int cx, int cy) +ui_set_clip(rdpInst *inst, int x, int y, int cx, int cy) { - struct mod* mod; + struct mod *mod; - mod = GET_MOD(inst); - mod->server_set_clip(mod, x, y, cx, cy); + mod = GET_MOD(inst); + mod->server_set_clip(mod, x, y, cx, cy); } /******************************************************************************/ static void DEFAULT_CC -ui_reset_clip(rdpInst* inst) +ui_reset_clip(rdpInst *inst) { - struct mod* mod; + struct mod *mod; - mod = GET_MOD(inst); - mod->server_reset_clip(mod); + mod = GET_MOD(inst); + mod->server_reset_clip(mod); } /******************************************************************************/ static void DEFAULT_CC -ui_resize_window(rdpInst* inst) +ui_resize_window(rdpInst *inst) { - g_writeln("ui_resize_window:"); + g_writeln("ui_resize_window:"); } /******************************************************************************/ static void DEFAULT_CC -ui_set_cursor(rdpInst* inst, RD_HCURSOR cursor) +ui_set_cursor(rdpInst *inst, RD_HCURSOR cursor) { - struct mod* mod; - struct my_cursor* cur; + struct mod *mod; + struct my_cursor *cur; - //g_writeln("ui_set_cursor:"); - mod = GET_MOD(inst); - cur = (struct my_cursor*)cursor; - if (cur != 0) - { - mod->server_set_cursor(mod, cur->hotx, cur->hoty, - cur->xormask, cur->andmask); - } - else - { - g_writeln("ui_set_cursor: nil cursor"); - } + //g_writeln("ui_set_cursor:"); + mod = GET_MOD(inst); + cur = (struct my_cursor *)cursor; + + if (cur != 0) + { + mod->server_set_cursor(mod, cur->hotx, cur->hoty, + cur->xormask, cur->andmask); + } + else + { + g_writeln("ui_set_cursor: nil cursor"); + } } /******************************************************************************/ static void DEFAULT_CC -ui_destroy_cursor(rdpInst* inst, RD_HCURSOR cursor) +ui_destroy_cursor(rdpInst *inst, RD_HCURSOR cursor) { - struct my_cursor* cur; + struct my_cursor *cur; - //g_writeln("ui_destroy_cursor:"); - cur = (struct my_cursor*)cursor; - if (cur != 0) - { - g_free(cur->andmask); - g_free(cur->xormask); - } - g_free(cur); + //g_writeln("ui_destroy_cursor:"); + cur = (struct my_cursor *)cursor; + + if (cur != 0) + { + g_free(cur->andmask); + g_free(cur->xormask); + } + + g_free(cur); } #define RGB24(_r, _g, _b) \ - (_r << 16) | (_g << 8) | _b; + (_r << 16) | (_g << 8) | _b; /******************************************************************************/ static int -l_get_pixel(tui8* data, int x, int y, int width, int height, int bpp) +l_get_pixel(tui8 *data, int x, int y, int width, int height, int bpp) { - int start; - int shift; - tui16* src16; - tui32* src32; - int red, green, blue; + int start; + int shift; + tui16 *src16; + tui32 *src32; + int red, green, blue; - switch (bpp) - { - case 1: - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - return (data[start] & (0x80 >> shift)) != 0; - case 8: - return data[y * width + x]; - case 15: - case 16: - src16 = (uint16*) data; - return src16[y * width + x]; - case 24: - data += y * width * 3; - data += x * 3; - red = data[0]; - green = data[1]; - blue = data[2]; - return RGB24(red, green, blue); - case 32: - src32 = (uint32*) data; - return src32[y * width + x]; - default: - g_writeln("l_get_pixel: unknown bpp %d", bpp); - break; - } + switch (bpp) + { + case 1: + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + return (data[start] & (0x80 >> shift)) != 0; + case 8: + return data[y * width + x]; + case 15: + case 16: + src16 = (uint16 *) data; + return src16[y * width + x]; + case 24: + data += y * width * 3; + data += x * 3; + red = data[0]; + green = data[1]; + blue = data[2]; + return RGB24(red, green, blue); + case 32: + src32 = (uint32 *) data; + return src32[y * width + x]; + default: + g_writeln("l_get_pixel: unknown bpp %d", bpp); + break; + } - return 0; + return 0; } /******************************************************************************/ static void -l_set_pixel(tui8* data, int x, int y, int width, int height, +l_set_pixel(tui8 *data, int x, int y, int width, int height, int bpp, int pixel) { - int start; - int shift; - int* dst32; - tui8* dst8; + int start; + int shift; + int *dst32; + tui8 *dst8; - if (bpp == 1) - { - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - if (pixel) - data[start] = data[start] | (0x80 >> shift); + if (bpp == 1) + { + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + + if (pixel) + { + data[start] = data[start] | (0x80 >> shift); + } + else + { + data[start] = data[start] & ~(0x80 >> shift); + } + } + else if (bpp == 24) + { + dst8 = data + (y * width + x) * 3; + *(dst8++) = (pixel >> 16) & 0xff; + *(dst8++) = (pixel >> 8) & 0xff; + *(dst8++) = (pixel >> 0) & 0xff; + } + else if (bpp == 32) + { + dst32 = (int *) data; + dst32[y * width + x] = pixel; + } else - data[start] = data[start] & ~(0x80 >> shift); - } - else if (bpp == 24) - { - dst8 = data + (y * width + x) * 3; - *(dst8++) = (pixel >> 16) & 0xff; - *(dst8++) = (pixel >> 8) & 0xff; - *(dst8++) = (pixel >> 0) & 0xff; - } - else if (bpp == 32) - { - dst32 = (int*) data; - dst32[y * width + x] = pixel; - } - else - { - g_writeln("l_set_pixel: unknown bpp %d", bpp); - } + { + g_writeln("l_set_pixel: unknown bpp %d", bpp); + } } @@ -752,269 +771,279 @@ l_set_pixel(tui8* data, int x, int y, int width, int height, /* andmask = mask = 32 * 32 / 8 xormask = data = 32 * 32 * 3 */ static RD_HCURSOR DEFAULT_CC -ui_create_cursor(rdpInst* inst, unsigned int x, unsigned int y, - int width, int height, uint8* andmask, - uint8* xormask, int bpp) +ui_create_cursor(rdpInst *inst, unsigned int x, unsigned int y, + int width, int height, uint8 *andmask, + uint8 *xormask, int bpp) { - struct mod* mod; - struct my_cursor* cur; - int i; - int j; - int jj; - int apixel; - int xpixel; - char* dst; + struct mod *mod; + struct my_cursor *cur; + int i; + int j; + int jj; + int apixel; + int xpixel; + char *dst; - mod = GET_MOD(inst); - g_writeln("ui_create_cursor: x %d y %d width %d height %d bpp %d", - x, y, width, height, bpp); - cur = (struct my_cursor*)g_malloc(sizeof(struct my_cursor), 1); - cur->width = width; - cur->height = height; - cur->hotx = x; - cur->hoty = y; - cur->andmask = g_malloc(32 * 32 * 4, 1); - cur->xormask = g_malloc(32 * 32 * 4, 1); - for (j = 0; j < height; j++) - { - jj = (bpp != 1) ? j : (height - 1) - j; - for (i = 0; i < width; i++) + mod = GET_MOD(inst); + g_writeln("ui_create_cursor: x %d y %d width %d height %d bpp %d", + x, y, width, height, bpp); + cur = (struct my_cursor *)g_malloc(sizeof(struct my_cursor), 1); + cur->width = width; + cur->height = height; + cur->hotx = x; + cur->hoty = y; + cur->andmask = g_malloc(32 * 32 * 4, 1); + cur->xormask = g_malloc(32 * 32 * 4, 1); + + for (j = 0; j < height; j++) { - apixel = l_get_pixel(andmask, i, jj, width, height, 1); - xpixel = l_get_pixel(xormask, i, jj, width, height, bpp); - xpixel = convert_color(bpp, 24, xpixel, mod->cmap); - l_set_pixel(cur->andmask, i, j, width, height, 1, apixel); - l_set_pixel(cur->xormask, i, j, width, height, 24, xpixel); + jj = (bpp != 1) ? j : (height - 1) - j; + + for (i = 0; i < width; i++) + { + apixel = l_get_pixel(andmask, i, jj, width, height, 1); + xpixel = l_get_pixel(xormask, i, jj, width, height, bpp); + xpixel = convert_color(bpp, 24, xpixel, mod->cmap); + l_set_pixel(cur->andmask, i, j, width, height, 1, apixel); + l_set_pixel(cur->xormask, i, j, width, height, 24, xpixel); + } } - } - return (RD_HCURSOR)cur; + + return (RD_HCURSOR)cur; } /******************************************************************************/ static void DEFAULT_CC -ui_set_null_cursor(rdpInst* inst) +ui_set_null_cursor(rdpInst *inst) { - g_writeln("ui_set_null_cursor:"); + g_writeln("ui_set_null_cursor:"); } /******************************************************************************/ static void DEFAULT_CC -ui_set_default_cursor(rdpInst* inst) +ui_set_default_cursor(rdpInst *inst) { - g_writeln("ui_set_default_cursor:"); + g_writeln("ui_set_default_cursor:"); } /******************************************************************************/ static RD_HPALETTE DEFAULT_CC -ui_create_palette(rdpInst* inst, RD_PALETTE* colors) +ui_create_palette(rdpInst *inst, RD_PALETTE *colors) { - struct mod* mod; - int index; - int red; - int green; - int blue; - int pixel; - int count; - int* cmap; + struct mod *mod; + int index; + int red; + int green; + int blue; + int pixel; + int count; + int *cmap; - mod = GET_MOD(inst); - g_writeln("ui_create_palette:"); - count = 256; - if (count > colors->count) - { - count = colors->count; - } - cmap = (int*)g_malloc(256 * 4, 1); - for (index = 0; index < count; index++) - { - red = colors->entries[index].red; - green = colors->entries[index].green; - blue = colors->entries[index].blue; - pixel = COLOR24RGB(red, green, blue); - cmap[index] = pixel; - } - return (RD_HPALETTE)cmap; + mod = GET_MOD(inst); + g_writeln("ui_create_palette:"); + count = 256; + + if (count > colors->count) + { + count = colors->count; + } + + cmap = (int *)g_malloc(256 * 4, 1); + + for (index = 0; index < count; index++) + { + red = colors->entries[index].red; + green = colors->entries[index].green; + blue = colors->entries[index].blue; + pixel = COLOR24RGB(red, green, blue); + cmap[index] = pixel; + } + + return (RD_HPALETTE)cmap; } /******************************************************************************/ static void DEFAULT_CC -ui_move_pointer(rdpInst* inst, int x, int y) +ui_move_pointer(rdpInst *inst, int x, int y) { - g_writeln("ui_move_pointer:"); + g_writeln("ui_move_pointer:"); } /******************************************************************************/ static void DEFAULT_CC -ui_set_palette(rdpInst* inst, RD_HPALETTE map) +ui_set_palette(rdpInst *inst, RD_HPALETTE map) { - struct mod* mod; + struct mod *mod; - mod = GET_MOD(inst); - g_writeln("ui_set_palette:"); - g_memcpy(mod->cmap, map, 256 * 4); - g_free(map); + mod = GET_MOD(inst); + g_writeln("ui_set_palette:"); + g_memcpy(mod->cmap, map, 256 * 4); + g_free(map); } /******************************************************************************/ static RD_HBITMAP DEFAULT_CC -ui_create_surface(rdpInst* inst, int width, int height, RD_HBITMAP old) +ui_create_surface(rdpInst *inst, int width, int height, RD_HBITMAP old) { - g_writeln("ui_create_surface:"); - return 0; + g_writeln("ui_create_surface:"); + return 0; } /******************************************************************************/ static void DEFAULT_CC -ui_set_surface(rdpInst* inst, RD_HBITMAP surface) +ui_set_surface(rdpInst *inst, RD_HBITMAP surface) { - g_writeln("ui_set_surface:"); + g_writeln("ui_set_surface:"); } /******************************************************************************/ static void DEFAULT_CC -ui_destroy_surface(rdpInst* inst, RD_HBITMAP surface) +ui_destroy_surface(rdpInst *inst, RD_HBITMAP surface) { - g_writeln("ui_destroy_surface:"); + g_writeln("ui_destroy_surface:"); } /******************************************************************************/ static void DEFAULT_CC -ui_channel_data(rdpInst* inst, int chan_id, char* data, int data_size, - int flags, int total_size) +ui_channel_data(rdpInst *inst, int chan_id, char *data, int data_size, + int flags, int total_size) { - g_writeln("ui_channel_data:"); + g_writeln("ui_channel_data:"); } /******************************************************************************/ static RD_BOOL DEFAULT_CC -ui_authenticate(rdpInst * inst) +ui_authenticate(rdpInst *inst) { - return 1; + return 1; } /******************************************************************************/ static int DEFAULT_CC -ui_decode(rdpInst * inst, uint8 * data, int data_size) +ui_decode(rdpInst *inst, uint8 *data, int data_size) { - return 0; + return 0; } /******************************************************************************/ static RD_BOOL DEFAULT_CC -ui_check_certificate(rdpInst * inst, const char * fingerprint, - const char * subject, const char * issuer, RD_BOOL verified) +ui_check_certificate(rdpInst *inst, const char *fingerprint, + const char *subject, const char *issuer, RD_BOOL verified) { - return 1; + return 1; } /******************************************************************************/ -struct mod* EXPORT_CC +struct mod *EXPORT_CC mod_init(void) { - struct mod* mod; + struct mod *mod; - //g_writeln("1"); - //freerdp_global_init(); - //g_writeln("2"); - mod = (struct mod*)g_malloc(sizeof(struct mod), 1); - mod->size = sizeof(struct mod); - mod->version = CURRENT_MOD_VER; - mod->handle = (tbus)mod; - mod->mod_connect = lib_mod_connect; - mod->mod_start = lib_mod_start; - mod->mod_event = lib_mod_event; - mod->mod_signal = lib_mod_signal; - mod->mod_end = lib_mod_end; - mod->mod_set_param = lib_mod_set_param; - mod->mod_session_change = mod_session_change; - mod->mod_get_wait_objs = mod_get_wait_objs; - mod->mod_check_wait_objs = mod_check_wait_objs; - mod->settings = (struct rdp_set*)g_malloc(sizeof(struct rdp_set), 1); + //g_writeln("1"); + //freerdp_global_init(); + //g_writeln("2"); + mod = (struct mod *)g_malloc(sizeof(struct mod), 1); + mod->size = sizeof(struct mod); + mod->version = CURRENT_MOD_VER; + mod->handle = (tbus)mod; + mod->mod_connect = lib_mod_connect; + mod->mod_start = lib_mod_start; + mod->mod_event = lib_mod_event; + mod->mod_signal = lib_mod_signal; + mod->mod_end = lib_mod_end; + mod->mod_set_param = lib_mod_set_param; + mod->mod_session_change = mod_session_change; + mod->mod_get_wait_objs = mod_get_wait_objs; + mod->mod_check_wait_objs = mod_check_wait_objs; + mod->settings = (struct rdp_set *)g_malloc(sizeof(struct rdp_set), 1); - mod->settings->width = 1280; - mod->settings->height = 1024; - mod->settings->encryption = 1; - mod->settings->rdp_security = 1; - mod->settings->tls_security = 1; - mod->settings->server_depth = 16; - mod->settings->bitmap_cache = 1; - mod->settings->bitmap_compression = 1; - mod->settings->performanceflags = - PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS; - mod->settings->new_cursors = 1; - mod->settings->rdp_version = 5; - mod->settings->text_flags = 1; + mod->settings->width = 1280; + mod->settings->height = 1024; + mod->settings->encryption = 1; + mod->settings->rdp_security = 1; + mod->settings->tls_security = 1; + mod->settings->server_depth = 16; + mod->settings->bitmap_cache = 1; + mod->settings->bitmap_compression = 1; + mod->settings->performanceflags = + PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS; + mod->settings->new_cursors = 1; + mod->settings->rdp_version = 5; + mod->settings->text_flags = 1; - mod->inst = freerdp_new(mod->settings); - if (mod->inst == 0) - { - return 0; - } - SET_MOD(mod->inst, mod); - mod->inst->ui_error = ui_error; - mod->inst->ui_warning = ui_warning; - mod->inst->ui_unimpl = ui_unimpl; - mod->inst->ui_begin_update = ui_begin_update; - mod->inst->ui_end_update = ui_end_update; - mod->inst->ui_desktop_save = ui_desktop_save; - mod->inst->ui_desktop_restore = ui_desktop_restore; - mod->inst->ui_create_bitmap = ui_create_bitmap; - mod->inst->ui_paint_bitmap = ui_paint_bitmap; - mod->inst->ui_destroy_bitmap = ui_destroy_bitmap; - mod->inst->ui_line = ui_line; - mod->inst->ui_rect = ui_rect; - mod->inst->ui_polygon = ui_polygon; - mod->inst->ui_polyline = ui_polyline; - mod->inst->ui_ellipse = ui_ellipse; - mod->inst->ui_add_char = ui_add_char; - mod->inst->ui_draw_text = ui_draw_text; - mod->inst->ui_start_draw_glyphs = ui_start_draw_glyphs; - mod->inst->ui_draw_glyph = ui_draw_glyph; - mod->inst->ui_end_draw_glyphs = ui_end_draw_glyphs; - mod->inst->ui_get_toggle_keys_state = ui_get_toggle_keys_state; - mod->inst->ui_bell = ui_bell; - mod->inst->ui_destblt = ui_destblt; - mod->inst->ui_patblt = ui_patblt; - mod->inst->ui_screenblt = ui_screenblt; - mod->inst->ui_memblt = ui_memblt; - mod->inst->ui_triblt = ui_triblt; - mod->inst->ui_create_glyph = ui_create_glyph; - mod->inst->ui_destroy_glyph = ui_destroy_glyph; - mod->inst->ui_select = ui_select; - mod->inst->ui_set_clip = ui_set_clip; - mod->inst->ui_reset_clip = ui_reset_clip; - mod->inst->ui_resize_window = ui_resize_window; - mod->inst->ui_set_cursor = ui_set_cursor; - mod->inst->ui_destroy_cursor = ui_destroy_cursor; - mod->inst->ui_create_cursor = ui_create_cursor; - mod->inst->ui_set_null_cursor = ui_set_null_cursor; - mod->inst->ui_set_default_cursor = ui_set_default_cursor; - mod->inst->ui_create_palette = ui_create_palette; - mod->inst->ui_move_pointer = ui_move_pointer; - mod->inst->ui_set_palette = ui_set_palette; - mod->inst->ui_create_surface = ui_create_surface; - mod->inst->ui_set_surface = ui_set_surface; - mod->inst->ui_destroy_surface = ui_destroy_surface; - mod->inst->ui_channel_data = ui_channel_data; + mod->inst = freerdp_new(mod->settings); - mod->inst->ui_authenticate = ui_authenticate; - mod->inst->ui_decode = ui_decode; - mod->inst->ui_check_certificate = ui_check_certificate; + if (mod->inst == 0) + { + return 0; + } - return mod; + SET_MOD(mod->inst, mod); + mod->inst->ui_error = ui_error; + mod->inst->ui_warning = ui_warning; + mod->inst->ui_unimpl = ui_unimpl; + mod->inst->ui_begin_update = ui_begin_update; + mod->inst->ui_end_update = ui_end_update; + mod->inst->ui_desktop_save = ui_desktop_save; + mod->inst->ui_desktop_restore = ui_desktop_restore; + mod->inst->ui_create_bitmap = ui_create_bitmap; + mod->inst->ui_paint_bitmap = ui_paint_bitmap; + mod->inst->ui_destroy_bitmap = ui_destroy_bitmap; + mod->inst->ui_line = ui_line; + mod->inst->ui_rect = ui_rect; + mod->inst->ui_polygon = ui_polygon; + mod->inst->ui_polyline = ui_polyline; + mod->inst->ui_ellipse = ui_ellipse; + mod->inst->ui_add_char = ui_add_char; + mod->inst->ui_draw_text = ui_draw_text; + mod->inst->ui_start_draw_glyphs = ui_start_draw_glyphs; + mod->inst->ui_draw_glyph = ui_draw_glyph; + mod->inst->ui_end_draw_glyphs = ui_end_draw_glyphs; + mod->inst->ui_get_toggle_keys_state = ui_get_toggle_keys_state; + mod->inst->ui_bell = ui_bell; + mod->inst->ui_destblt = ui_destblt; + mod->inst->ui_patblt = ui_patblt; + mod->inst->ui_screenblt = ui_screenblt; + mod->inst->ui_memblt = ui_memblt; + mod->inst->ui_triblt = ui_triblt; + mod->inst->ui_create_glyph = ui_create_glyph; + mod->inst->ui_destroy_glyph = ui_destroy_glyph; + mod->inst->ui_select = ui_select; + mod->inst->ui_set_clip = ui_set_clip; + mod->inst->ui_reset_clip = ui_reset_clip; + mod->inst->ui_resize_window = ui_resize_window; + mod->inst->ui_set_cursor = ui_set_cursor; + mod->inst->ui_destroy_cursor = ui_destroy_cursor; + mod->inst->ui_create_cursor = ui_create_cursor; + mod->inst->ui_set_null_cursor = ui_set_null_cursor; + mod->inst->ui_set_default_cursor = ui_set_default_cursor; + mod->inst->ui_create_palette = ui_create_palette; + mod->inst->ui_move_pointer = ui_move_pointer; + mod->inst->ui_set_palette = ui_set_palette; + mod->inst->ui_create_surface = ui_create_surface; + mod->inst->ui_set_surface = ui_set_surface; + mod->inst->ui_destroy_surface = ui_destroy_surface; + mod->inst->ui_channel_data = ui_channel_data; + + mod->inst->ui_authenticate = ui_authenticate; + mod->inst->ui_decode = ui_decode; + mod->inst->ui_check_certificate = ui_check_certificate; + + return mod; } /******************************************************************************/ int EXPORT_CC -mod_exit(struct mod* mod) +mod_exit(struct mod *mod) { - if (mod == 0) - { + if (mod == 0) + { + return 0; + } + + freerdp_free(mod->inst); + g_free(mod->settings); + g_free(mod); + //freerdp_global_finish(); return 0; - } - freerdp_free(mod->inst); - g_free(mod->settings); - g_free(mod); - //freerdp_global_finish(); - return 0; } diff --git a/freerdp/xrdp-freerdp.h b/freerdp/xrdp-freerdp.h index cd931003..b62c8206 100644 --- a/freerdp/xrdp-freerdp.h +++ b/freerdp/xrdp-freerdp.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2010 - - freerdp wrapper - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * freerdp wrapper + */ /* include other h files */ #include "arch.h" diff --git a/freerdp1/xrdp-color.c b/freerdp1/xrdp-color.c index ef74d1c5..6b99140a 100644 --- a/freerdp1/xrdp-color.c +++ b/freerdp1/xrdp-color.c @@ -19,258 +19,295 @@ #include "xrdp-freerdp.h" -char* APP_CC -convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, - int width, int height, int* palette) +char *APP_CC +convert_bitmap(int in_bpp, int out_bpp, char *bmpdata, + int width, int height, int *palette) { - char* out; - char* src; - char* dst; - int i; - int j; - int red; - int green; - int blue; - int pixel; + char *out; + char *src; + char *dst; + int i; + int j; + int red; + int green; + int blue; + int pixel; - if ((in_bpp == 8) && (out_bpp == 8)) - { - out = (char*)g_malloc(width * height, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + if ((in_bpp == 8) && (out_bpp == 8)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - *dst = pixel; - src++; - dst++; - } + out = (char *)g_malloc(width * height, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + *dst = pixel; + src++; + dst++; + } + } + + return out; } - return out; - } - if ((in_bpp == 8) && (out_bpp == 16)) - { - out = (char*)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 8) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16*)dst) = pixel; - src++; - dst += 2; - } + out = (char *)g_malloc(width * height * 2, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *((tui16 *)dst) = pixel; + src++; + dst += 2; + } + } + + return out; } - return out; - } - if ((in_bpp == 8) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 8) && (out_bpp == 24)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src++; - dst += 4; - } + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src++; + dst += 4; + } + } + + return out; } - return out; - } - if ((in_bpp == 15) && (out_bpp == 16)) - { - out = (char*)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 15) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16*)dst) = pixel; - src += 2; - dst += 2; - } + out = (char *)g_malloc(width * height * 2, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *((tui16 *)dst) = pixel; + src += 2; + dst += 2; + } + } + + return out; } - return out; - } - if ((in_bpp == 15) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 15) && (out_bpp == 24)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src += 2; - dst += 4; - } + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src += 2; + dst += 4; + } + } + + return out; } - return out; - } - if ((in_bpp == 15) && (out_bpp == 15)) - { - return bmpdata; - } - if ((in_bpp == 16) && (out_bpp == 16)) - { - return bmpdata; - } - if ((in_bpp == 16) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 15) && (out_bpp == 15)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src += 2; - dst += 4; - } + return bmpdata; } - return out; - } - if ((in_bpp == 24) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 16) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - blue = *((tui8*)src); - src++; - green = *((tui8*)src); - src++; - red = *((tui8*)src); - src++; - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - dst += 4; - } + return bmpdata; } - return out; - } - if ((in_bpp == 32) && (out_bpp == 24)) - { - return bmpdata; - } - if ((in_bpp == 32) && (out_bpp == 32)) - { - return bmpdata; - } - g_writeln("convert_bitmap: error unknown conversion from %d to %d", - in_bpp, out_bpp); - return 0; + + if ((in_bpp == 16) && (out_bpp == 24)) + { + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR16(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src += 2; + dst += 4; + } + } + + return out; + } + + if ((in_bpp == 24) && (out_bpp == 24)) + { + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + blue = *((tui8 *)src); + src++; + green = *((tui8 *)src); + src++; + red = *((tui8 *)src); + src++; + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + dst += 4; + } + } + + return out; + } + + if ((in_bpp == 32) && (out_bpp == 24)) + { + return bmpdata; + } + + if ((in_bpp == 32) && (out_bpp == 32)) + { + return bmpdata; + } + + g_writeln("convert_bitmap: error unknown conversion from %d to %d", + in_bpp, out_bpp); + return 0; } /*****************************************************************************/ /* returns color or 0 */ int APP_CC -convert_color(int in_bpp, int out_bpp, int in_color, int* palette) +convert_color(int in_bpp, int out_bpp, int in_color, int *palette) { - int pixel; - int red; - int green; - int blue; + int pixel; + int red; + int green; + int blue; - if ((in_bpp == 1) && (out_bpp == 24)) - { - pixel = in_color == 0 ? 0 : 0xffffff; - return pixel; - } - if ((in_bpp == 8) && (out_bpp == 8)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - return pixel; - } - if ((in_bpp == 8) && (out_bpp == 16)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - if ((in_bpp == 8) && (out_bpp == 24)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 15) && (out_bpp == 16)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - if ((in_bpp == 15) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 15) && (out_bpp == 15)) - { - return in_color; - } - if ((in_bpp == 16) && (out_bpp == 16)) - { - return in_color; - } - if ((in_bpp == 16) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 24) && (out_bpp == 24)) - { - return in_color; - } - if ((in_bpp == 32) && (out_bpp == 24)) - { - return in_color; - } - if ((in_bpp == 32) && (out_bpp == 32)) - { - return in_color; - } - g_writeln("convert_color: error unknown conversion from %d to %d", - in_bpp, out_bpp); - return 0; + if ((in_bpp == 1) && (out_bpp == 24)) + { + pixel = in_color == 0 ? 0 : 0xffffff; + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 8)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 16)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 24)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 16)) + { + pixel = in_color; + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 24)) + { + pixel = in_color; + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 15)) + { + return in_color; + } + + if ((in_bpp == 16) && (out_bpp == 16)) + { + return in_color; + } + + if ((in_bpp == 16) && (out_bpp == 24)) + { + pixel = in_color; + SPLITCOLOR16(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 24) && (out_bpp == 24)) + { + return in_color; + } + + if ((in_bpp == 32) && (out_bpp == 24)) + { + return in_color; + } + + if ((in_bpp == 32) && (out_bpp == 32)) + { + return in_color; + } + + g_writeln("convert_color: error unknown conversion from %d to %d", + in_bpp, out_bpp); + return 0; } diff --git a/freerdp1/xrdp-freerdp.c b/freerdp1/xrdp-freerdp.c index 524dcf2e..25206f8e 100644 --- a/freerdp1/xrdp-freerdp.c +++ b/freerdp1/xrdp-freerdp.c @@ -23,1659 +23,1735 @@ #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { g_write _args ; } } while (0) + do { if (_level < LOG_LEVEL) { g_write _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0) + do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0) struct mod_context { - rdpContext _p; - struct mod* modi; + rdpContext _p; + struct mod *modi; }; typedef struct mod_context modContext; /*****************************************************************************/ /* return error */ static int DEFAULT_CC -lxrdp_start(struct mod* mod, int w, int h, int bpp) +lxrdp_start(struct mod *mod, int w, int h, int bpp) { - rdpSettings* settings; + rdpSettings *settings; - LLOGLN(10, ("lxrdp_start: w %d h %d bpp %d", w, h, bpp)); - settings = mod->inst->settings; - settings->width = w; - settings->height = h; - settings->color_depth = bpp; - mod->bpp = bpp; + LLOGLN(10, ("lxrdp_start: w %d h %d bpp %d", w, h, bpp)); + settings = mod->inst->settings; + settings->width = w; + settings->height = h; + settings->color_depth = bpp; + mod->bpp = bpp; - settings->encryption = 1; - settings->tls_security = 1; - settings->nla_security = 0; - settings->rdp_security = 1; + settings->encryption = 1; + settings->tls_security = 1; + settings->nla_security = 0; + settings->rdp_security = 1; - return 0; + return 0; } /******************************************************************************/ /* return error */ static int DEFAULT_CC -lxrdp_connect(struct mod* mod) +lxrdp_connect(struct mod *mod) { - boolean ok; + boolean ok; - LLOGLN(10, ("lxrdp_connect:")); + LLOGLN(10, ("lxrdp_connect:")); - ok = freerdp_connect(mod->inst); - LLOGLN(0, ("lxrdp_connect: freerdp_connect returned %d", ok)); + ok = freerdp_connect(mod->inst); + LLOGLN(0, ("lxrdp_connect: freerdp_connect returned %d", ok)); - if (!ok) - { - LLOGLN(0, ("Failure to connect")); -#ifdef ERRORSTART - if (connectErrorCode != 0) + if (!ok) { - char buf[128]; + LLOGLN(0, ("Failure to connect")); +#ifdef ERRORSTART - if (connectErrorCode < ERRORSTART) - { - if (strerror_r(connectErrorCode, buf, 128) != 0) + if (connectErrorCode != 0) { - snprintf(buf, 128, "Errorcode from connect : %d", connectErrorCode); - } - } - else - { - switch (connectErrorCode) - { - case PREECONNECTERROR: - snprintf(buf, 128, "The error code from connect is " - "PREECONNECTERROR"); - break; - case UNDEFINEDCONNECTERROR: - snprintf(buf, 128, "The error code from connect is " - "UNDEFINEDCONNECTERROR"); - break; - case POSTCONNECTERROR: - snprintf(buf, 128, "The error code from connect is " - "POSTCONNECTERROR"); - break; - case DNSERROR: - snprintf(buf, 128, "The DNS system generated an error"); - break; - case DNSNAMENOTFOUND: - snprintf(buf, 128, "The DNS system could not find the " - "specified name"); - break; - case CONNECTERROR: - snprintf(buf, 128, "A general connect error was returned"); - break; - case MCSCONNECTINITIALERROR: - snprintf(buf, 128, "The error code from connect is " - "MCSCONNECTINITIALERROR"); - break; - case TLSCONNECTERROR: - snprintf(buf, 128, "Error in TLS handshake"); - break; - case AUTHENTICATIONERROR: - snprintf(buf, 128, "Authentication error check your password " - "and username"); - break; - default: - snprintf(buf, 128, "Unhandled Errorcode from connect : %d", - connectErrorCode); - break; - } - } - mod->server_msg(mod, buf, 0); - } -#endif - return 1; - } - return 0; -} + char buf[128]; -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_event(struct mod* mod, int msg, long param1, long param2, - long param3, long param4) -{ - int x; - int y; - int flags; - int size; - int total_size; - int chanid; - int lchid; - char* data; - - LLOGLN(10, ("lxrdp_event: msg %d", msg)); - switch (msg) - { - case 15: /* key down */ - mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); - break; - case 16: /* key up */ - mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); - break; - case 17: /*Synchronize*/ - LLOGLN(0, ("Synchronized event handled")); - mod->inst->input->SynchronizeEvent(mod->inst->input, 0); - break; - case 100: /* mouse move */ - LLOGLN(10, ("mouse move %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_MOVE; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 101: /* left button up */ - LLOGLN(10, ("left button up %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON1; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 102: /* left button down */ - LLOGLN(10, ("left button down %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON1 | PTR_FLAGS_DOWN; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 103: /* right button up */ - LLOGLN(10, ("right button up %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON2; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 104: /* right button down */ - LLOGLN(10, ("right button down %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON2 | PTR_FLAGS_DOWN; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 105: /* middle button up */ - LLOGLN(10, ("middle button up %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON3; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 106: /* middle button down */ - LLOGLN(10, ("middle button down %d %d", param1, param2)); - x = param1; - y = param2; - flags = PTR_FLAGS_BUTTON3 | PTR_FLAGS_DOWN; - mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); - break; - case 107: /* wheel up */ - flags = PTR_FLAGS_WHEEL | 0x0078; - mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); - case 108: - break; - case 109: /* wheel down */ - flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; - mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); - case 110: - break; - case 200: - LLOGLN(10, ("Invalidate request sent from client")); - RECTANGLE_16 *rectangle = (RECTANGLE_16 *) g_malloc(sizeof(RECTANGLE_16), 0); - /* The parameters are coded as follows param1 = MAKELONG(y, x), param2 =MAKELONG(h, w) - * #define MAKELONG(lo, hi) ((((hi) & 0xffff) << 16) | ((lo) & 0xffff)) - */ - rectangle->left = (param1 >> 16) & 0xffff; - rectangle->top = param1 & 0xffff; - rectangle->right = (((param2 >> 16) & 0xffff) + rectangle->left) - 1; - rectangle->bottom = ((param2 & 0xffff) + rectangle->top) - 1; - if (mod->inst->settings->refresh_rect) - { - if (mod->inst->update != NULL) - { - if (mod->inst->update->RefreshRect != NULL) - { - if (mod->inst->context != NULL) + if (connectErrorCode < ERRORSTART) { - LLOGLN(0, ("update rectangle left: %d top: %d bottom: %d right: %d", - rectangle->left, rectangle->top, rectangle->bottom, rectangle->right)); - mod->inst->update->RefreshRect(mod->inst->context, 1, rectangle); + if (strerror_r(connectErrorCode, buf, 128) != 0) + { + snprintf(buf, 128, "Errorcode from connect : %d", connectErrorCode); + } } else { - LLOGLN(0, ("Invalidate request -The context is null")); + switch (connectErrorCode) + { + case PREECONNECTERROR: + snprintf(buf, 128, "The error code from connect is " + "PREECONNECTERROR"); + break; + case UNDEFINEDCONNECTERROR: + snprintf(buf, 128, "The error code from connect is " + "UNDEFINEDCONNECTERROR"); + break; + case POSTCONNECTERROR: + snprintf(buf, 128, "The error code from connect is " + "POSTCONNECTERROR"); + break; + case DNSERROR: + snprintf(buf, 128, "The DNS system generated an error"); + break; + case DNSNAMENOTFOUND: + snprintf(buf, 128, "The DNS system could not find the " + "specified name"); + break; + case CONNECTERROR: + snprintf(buf, 128, "A general connect error was returned"); + break; + case MCSCONNECTINITIALERROR: + snprintf(buf, 128, "The error code from connect is " + "MCSCONNECTINITIALERROR"); + break; + case TLSCONNECTERROR: + snprintf(buf, 128, "Error in TLS handshake"); + break; + case AUTHENTICATIONERROR: + snprintf(buf, 128, "Authentication error check your password " + "and username"); + break; + default: + snprintf(buf, 128, "Unhandled Errorcode from connect : %d", + connectErrorCode); + break; + } } - } - else - { - LLOGLN(0, ("Invalidate request - RefreshRect is Null")); - } + + mod->server_msg(mod, buf, 0); + } + +#endif + return 1; + } + + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_event(struct mod *mod, int msg, long param1, long param2, + long param3, long param4) +{ + int x; + int y; + int flags; + int size; + int total_size; + int chanid; + int lchid; + char *data; + + LLOGLN(10, ("lxrdp_event: msg %d", msg)); + + switch (msg) + { + case 15: /* key down */ + mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); + break; + case 16: /* key up */ + mod->inst->input->KeyboardEvent(mod->inst->input, param4, param3); + break; + case 17: /*Synchronize*/ + LLOGLN(0, ("Synchronized event handled")); + mod->inst->input->SynchronizeEvent(mod->inst->input, 0); + break; + case 100: /* mouse move */ + LLOGLN(10, ("mouse move %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_MOVE; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 101: /* left button up */ + LLOGLN(10, ("left button up %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON1; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 102: /* left button down */ + LLOGLN(10, ("left button down %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON1 | PTR_FLAGS_DOWN; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 103: /* right button up */ + LLOGLN(10, ("right button up %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON2; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 104: /* right button down */ + LLOGLN(10, ("right button down %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON2 | PTR_FLAGS_DOWN; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 105: /* middle button up */ + LLOGLN(10, ("middle button up %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON3; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 106: /* middle button down */ + LLOGLN(10, ("middle button down %d %d", param1, param2)); + x = param1; + y = param2; + flags = PTR_FLAGS_BUTTON3 | PTR_FLAGS_DOWN; + mod->inst->input->MouseEvent(mod->inst->input, flags, x, y); + break; + case 107: /* wheel up */ + flags = PTR_FLAGS_WHEEL | 0x0078; + mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); + case 108: + break; + case 109: /* wheel down */ + flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; + mod->inst->input->MouseEvent(mod->inst->input, flags, 0, 0); + case 110: + break; + case 200: + LLOGLN(10, ("Invalidate request sent from client")); + RECTANGLE_16 *rectangle = (RECTANGLE_16 *) g_malloc(sizeof(RECTANGLE_16), 0); + /* The parameters are coded as follows param1 = MAKELONG(y, x), param2 =MAKELONG(h, w) + * #define MAKELONG(lo, hi) ((((hi) & 0xffff) << 16) | ((lo) & 0xffff)) + */ + rectangle->left = (param1 >> 16) & 0xffff; + rectangle->top = param1 & 0xffff; + rectangle->right = (((param2 >> 16) & 0xffff) + rectangle->left) - 1; + rectangle->bottom = ((param2 & 0xffff) + rectangle->top) - 1; + + if (mod->inst->settings->refresh_rect) + { + if (mod->inst->update != NULL) + { + if (mod->inst->update->RefreshRect != NULL) + { + if (mod->inst->context != NULL) + { + LLOGLN(0, ("update rectangle left: %d top: %d bottom: %d right: %d", + rectangle->left, rectangle->top, rectangle->bottom, rectangle->right)); + mod->inst->update->RefreshRect(mod->inst->context, 1, rectangle); + } + else + { + LLOGLN(0, ("Invalidate request -The context is null")); + } + } + else + { + LLOGLN(0, ("Invalidate request - RefreshRect is Null")); + } + } + else + { + LLOGLN(0, ("Invalidate request -the update pointer is null")); + } + } + else + { + LLOGLN(0, ("Invalidate request - warning - update rectangle is disabled")); + } + + g_free(rectangle); + break; + case 0x5555: + chanid = LOWORD(param1); + flags = HIWORD(param1); + size = (int)param2; + data = (char *)param3; + total_size = (int)param4; + LLOGLN(10, ("lxrdp_event: client to server flags %d", flags)); + + if ((chanid < 0) || (chanid >= mod->inst->settings->num_channels)) + { + LLOGLN(0, ("lxrdp_event: error chanid %d", chanid)); + break; + } + + lchid = mod->inst->settings->channels[chanid].channel_id; + + switch (flags & 3) + { + case 3: + mod->inst->SendChannelData(mod->inst, lchid, (tui8 *)data, total_size); + break; + case 2: + /* end */ + g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); + mod->chan_buf_valid += size; + mod->inst->SendChannelData(mod->inst, lchid, (tui8 *)(mod->chan_buf), + total_size); + g_free(mod->chan_buf); + mod->chan_buf = 0; + mod->chan_buf_bytes = 0; + mod->chan_buf_valid = 0; + break; + case 1: + /* start */ + g_free(mod->chan_buf); + mod->chan_buf = (char *)g_malloc(total_size, 0); + mod->chan_buf_bytes = total_size; + mod->chan_buf_valid = 0; + g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); + mod->chan_buf_valid += size; + break; + default: + /* middle */ + g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); + mod->chan_buf_valid += size; + break; + } + + break; + default: + LLOGLN(0, ("Unhandled message type in eventhandler %d", msg)); + break; + } + + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_signal(struct mod *mod) +{ + LLOGLN(10, ("lxrdp_signal:")); + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_end(struct mod *mod) +{ + int i; + int j; + + for (j = 0; j < 4; j++) + { + for (i = 0; i < 4096; i++) + { + g_free(mod->bitmap_cache[j][i].data); + } + } + + for (i = 0; i < 64; i++) + { + if (mod->brush_cache[i].data != mod->brush_cache[i].b8x8) + { + g_free(mod->brush_cache[i].data); + } + } + + LLOGLN(10, ("lxrdp_end:")); + return 0; +} + +/******************************************************************************/ +/* return error */ +static int DEFAULT_CC +lxrdp_set_param(struct mod *mod, char *name, char *value) +{ + rdpSettings *settings; + + LLOGLN(10, ("lxrdp_set_param: name [%s] value [%s]", name, value)); + settings = mod->inst->settings; + + LLOGLN(10, ("%p %d", settings->hostname, settings->encryption)); + + if (g_strcmp(name, "hostname") == 0) + { + } + else if (g_strcmp(name, "ip") == 0) + { + settings->hostname = g_strdup(value); + } + else if (g_strcmp(name, "port") == 0) + { + settings->port = g_atoi(value); + } + else if (g_strcmp(name, "keylayout") == 0) + { + } + else if (g_strcmp(name, "name") == 0) + { + } + else if (g_strcmp(name, "lib") == 0) + { + } + else if (g_strcmp(name, "username") == 0) + { + g_strncpy(mod->username, value, 255); + } + else if (g_strcmp(name, "password") == 0) + { + g_strncpy(mod->password, value, 255); + } + else if (g_strcmp(name, "client_info") == 0) + { + g_memcpy(&(mod->client_info), value, sizeof(mod->client_info)); + /* This is a Struct and cannot be printed in next else*/ + LLOGLN(10, ("Client_info struct ignored")); + } + else + { + LLOGLN(0, ("lxrdp_set_param: unknown name [%s] value [%s]", name, value)); + } + + return 0; +} + +/******************************************************************************/ +static int DEFAULT_CC +lxrdp_session_change(struct mod *mod, int a, int b) +{ + LLOGLN(10, ("lxrdp_session_change:")); + return 0; +} + +/******************************************************************************/ +static int DEFAULT_CC +lxrdp_get_wait_objs(struct mod *mod, tbus *read_objs, int *rcount, + tbus *write_objs, int *wcount, int *timeout) +{ + void **rfds; + void **wfds; + boolean ok; + + LLOGLN(10, ("lxrdp_get_wait_objs:")); + rfds = (void **)read_objs; + wfds = (void **)write_objs; + ok = freerdp_get_fds(mod->inst, rfds, rcount, wfds, wcount); + + if (!ok) + { + LLOGLN(0, ("lxrdp_get_wait_objs: freerdp_get_fds failed")); + return 1; + } + + return 0; +} + +/******************************************************************************/ +static int DEFAULT_CC +lxrdp_check_wait_objs(struct mod *mod) +{ + boolean ok; + + LLOGLN(10, ("lxrdp_check_wait_objs:")); + ok = freerdp_check_fds(mod->inst); + + if (!ok) + { + LLOGLN(0, ("lxrdp_check_wait_objs: freerdp_check_fds failed")); + return 1; + } + + return 0; +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_begin_paint(rdpContext *context) +{ + struct mod *mod; + + LLOGLN(10, ("lfreerdp_begin_paint:")); + mod = ((struct mod_context *)context)->modi; + mod->server_begin_update(mod); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_end_paint(rdpContext *context) +{ + struct mod *mod; + + LLOGLN(10, ("lfreerdp_end_paint:")); + mod = ((struct mod_context *)context)->modi; + mod->server_end_update(mod); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_set_bounds(rdpContext *context, rdpBounds *bounds) +{ + struct mod *mod; + int x; + int y; + int cx; + int cy; + + LLOGLN(10, ("lfreerdp_set_bounds: %p", bounds)); + mod = ((struct mod_context *)context)->modi; + + if (bounds != 0) + { + x = bounds->left; + y = bounds->top; + cx = (bounds->right - bounds->left) + 1; + cy = (bounds->bottom - bounds->top) + 1; + mod->server_set_clip(mod, x, y, cx, cy); + } + else + { + mod->server_reset_clip(mod); + } +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_bitmap_update(rdpContext *context, BITMAP_UPDATE *bitmap) +{ + struct mod *mod; + int index; + int cx; + int cy; + int server_bpp; + int server_Bpp; + int client_bpp; + int j; + int line_bytes; + BITMAP_DATA *bd; + char *dst_data; + char *dst_data1; + char *src; + char *dst; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_bitmap_update: %d %d", bitmap->number, bitmap->count)); + + server_bpp = mod->inst->settings->color_depth; + server_Bpp = (server_bpp + 7) / 8; + client_bpp = mod->bpp; + + for (index = 0; index < bitmap->number; index++) + { + bd = bitmap->rectangles + index; + cx = (bd->destRight - bd->destLeft) + 1; + cy = (bd->destBottom - bd->destTop) + 1; + line_bytes = server_Bpp * bd->width; + dst_data = (char *)g_malloc(bd->height * line_bytes + 16, 0); + + if (bd->compressed) + { + bitmap_decompress(bd->bitmapDataStream, (tui8 *)dst_data, bd->width, + bd->height, bd->bitmapLength, server_bpp, server_bpp); } else { - LLOGLN(0, ("Invalidate request -the update pointer is null")); + /* bitmap is upside down */ + src = (char *)(bd->bitmapDataStream); + dst = dst_data + bd->height * line_bytes; + + for (j = 0; j < bd->height; j++) + { + dst -= line_bytes; + g_memcpy(dst, src, line_bytes); + src += line_bytes; + } } - } - else - { - LLOGLN(0, ("Invalidate request - warning - update rectangle is disabled")); - } - g_free(rectangle); - break; - case 0x5555: - chanid = LOWORD(param1); - flags = HIWORD(param1); - size = (int)param2; - data = (char*)param3; - total_size = (int)param4; - LLOGLN(10, ("lxrdp_event: client to server flags %d", flags)); - if ((chanid < 0) || (chanid >= mod->inst->settings->num_channels)) - { - LLOGLN(0, ("lxrdp_event: error chanid %d", chanid)); - break; - } - lchid = mod->inst->settings->channels[chanid].channel_id; - switch (flags & 3) - { - case 3: - mod->inst->SendChannelData(mod->inst, lchid, (tui8*)data, total_size); - break; - case 2: - /* end */ - g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); - mod->chan_buf_valid += size; - mod->inst->SendChannelData(mod->inst, lchid, (tui8*)(mod->chan_buf), - total_size); - g_free(mod->chan_buf); - mod->chan_buf = 0; - mod->chan_buf_bytes = 0; - mod->chan_buf_valid = 0; - break; - case 1: - /* start */ - g_free(mod->chan_buf); - mod->chan_buf = (char*)g_malloc(total_size, 0); - mod->chan_buf_bytes = total_size; - mod->chan_buf_valid = 0; - g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); - mod->chan_buf_valid += size; - break; - default: - /* middle */ - g_memcpy(mod->chan_buf + mod->chan_buf_valid, data, size); - mod->chan_buf_valid += size; - break; - } - break; - default: - LLOGLN(0, ("Unhandled message type in eventhandler %d", msg)); - break; - } - return 0; -} -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_signal(struct mod* mod) -{ - LLOGLN(10, ("lxrdp_signal:")); - return 0; -} + dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, + bd->width, bd->height, mod->colormap); + mod->server_paint_rect(mod, bd->destLeft, bd->destTop, cx, cy, + dst_data1, bd->width, bd->height, 0, 0); -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_end(struct mod* mod) -{ - int i; - int j; + if (dst_data1 != dst_data) + { + g_free(dst_data1); + } - for (j = 0; j < 4; j++) - { - for (i = 0; i < 4096; i++) - { - g_free(mod->bitmap_cache[j][i].data); + g_free(dst_data); } - } - for (i = 0; i < 64; i++) - { - if (mod->brush_cache[i].data != mod->brush_cache[i].b8x8) +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_dst_blt(rdpContext *context, DSTBLT_ORDER *dstblt) +{ + struct mod *mod; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_dst_blt:")); + mod->server_set_opcode(mod, dstblt->bRop); + mod->server_fill_rect(mod, dstblt->nLeftRect, dstblt->nTopRect, + dstblt->nWidth, dstblt->nHeight); + mod->server_set_opcode(mod, 0xcc); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pat_blt(rdpContext *context, PATBLT_ORDER *patblt) +{ + struct mod *mod; + int idx; + int fgcolor; + int bgcolor; + int server_bpp; + int client_bpp; + struct brush_item *bi; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_pat_blt:")); + + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + LLOGLN(0, ("lfreerdp_pat_blt: bpp %d %d", server_bpp, client_bpp)); + + fgcolor = convert_color(server_bpp, client_bpp, + patblt->foreColor, mod->colormap); + bgcolor = convert_color(server_bpp, client_bpp, + patblt->backColor, mod->colormap); + + mod->server_set_mixmode(mod, 1); + mod->server_set_opcode(mod, patblt->bRop); + mod->server_set_fgcolor(mod, fgcolor); + mod->server_set_bgcolor(mod, bgcolor); + + if (patblt->brush.style & 0x80) { - g_free(mod->brush_cache[i].data); - } - } - LLOGLN(10, ("lxrdp_end:")); - return 0; -} + idx = patblt->brush.hatch; -/******************************************************************************/ -/* return error */ -static int DEFAULT_CC -lxrdp_set_param(struct mod* mod, char* name, char* value) -{ - rdpSettings* settings; + if ((idx < 0) || (idx >= 64)) + { + LLOGLN(0, ("lfreerdp_pat_blt: error")); + return; + } - LLOGLN(10, ("lxrdp_set_param: name [%s] value [%s]", name, value)); - settings = mod->inst->settings; - - LLOGLN(10, ("%p %d", settings->hostname, settings->encryption)); - - if (g_strcmp(name, "hostname") == 0) - { - } - else if (g_strcmp(name, "ip") == 0) - { - settings->hostname = g_strdup(value); - } - else if (g_strcmp(name, "port") == 0) - { - settings->port = g_atoi(value); - } - else if (g_strcmp(name, "keylayout") == 0) - { - } - else if (g_strcmp(name, "name") == 0) - { - } - else if (g_strcmp(name, "lib") == 0) - { - } - else if (g_strcmp(name, "username") == 0) - { - g_strncpy(mod->username, value, 255); - } - else if (g_strcmp(name, "password") == 0) - { - g_strncpy(mod->password, value, 255); - } - else if (g_strcmp(name, "client_info") == 0) - { - g_memcpy(&(mod->client_info), value, sizeof(mod->client_info)); - /* This is a Struct and cannot be printed in next else*/ - LLOGLN(10, ("Client_info struct ignored")); - } - else - { - LLOGLN(0, ("lxrdp_set_param: unknown name [%s] value [%s]", name, value)); - } - - return 0; -} - -/******************************************************************************/ -static int DEFAULT_CC -lxrdp_session_change(struct mod* mod, int a, int b) -{ - LLOGLN(10, ("lxrdp_session_change:")); - return 0; -} - -/******************************************************************************/ -static int DEFAULT_CC -lxrdp_get_wait_objs(struct mod* mod, tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout) -{ - void** rfds; - void** wfds; - boolean ok; - - LLOGLN(10, ("lxrdp_get_wait_objs:")); - rfds = (void**)read_objs; - wfds = (void**)write_objs; - ok = freerdp_get_fds(mod->inst, rfds, rcount, wfds, wcount); - if (!ok) - { - LLOGLN(0, ("lxrdp_get_wait_objs: freerdp_get_fds failed")); - return 1; - } - return 0; -} - -/******************************************************************************/ -static int DEFAULT_CC -lxrdp_check_wait_objs(struct mod* mod) -{ - boolean ok; - - LLOGLN(10, ("lxrdp_check_wait_objs:")); - ok = freerdp_check_fds(mod->inst); - if (!ok) - { - LLOGLN(0, ("lxrdp_check_wait_objs: freerdp_check_fds failed")); - return 1; - } - return 0; -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_begin_paint(rdpContext* context) -{ - struct mod* mod; - - LLOGLN(10, ("lfreerdp_begin_paint:")); - mod = ((struct mod_context*)context)->modi; - mod->server_begin_update(mod); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_end_paint(rdpContext* context) -{ - struct mod* mod; - - LLOGLN(10, ("lfreerdp_end_paint:")); - mod = ((struct mod_context*)context)->modi; - mod->server_end_update(mod); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_set_bounds(rdpContext* context, rdpBounds* bounds) -{ - struct mod* mod; - int x; - int y; - int cx; - int cy; - - LLOGLN(10, ("lfreerdp_set_bounds: %p", bounds)); - mod = ((struct mod_context*)context)->modi; - if (bounds != 0) - { - x = bounds->left; - y = bounds->top; - cx = (bounds->right - bounds->left) + 1; - cy = (bounds->bottom - bounds->top) + 1; - mod->server_set_clip(mod, x, y, cx, cy); - } - else - { - mod->server_reset_clip(mod); - } -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap) -{ - struct mod* mod; - int index; - int cx; - int cy; - int server_bpp; - int server_Bpp; - int client_bpp; - int j; - int line_bytes; - BITMAP_DATA* bd; - char* dst_data; - char* dst_data1; - char* src; - char* dst; - - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_bitmap_update: %d %d", bitmap->number, bitmap->count)); - - server_bpp = mod->inst->settings->color_depth; - server_Bpp = (server_bpp + 7) / 8; - client_bpp = mod->bpp; - - for (index = 0; index < bitmap->number; index++) - { - bd = bitmap->rectangles + index; - cx = (bd->destRight - bd->destLeft) + 1; - cy = (bd->destBottom - bd->destTop) + 1; - line_bytes = server_Bpp * bd->width; - dst_data = (char*)g_malloc(bd->height * line_bytes + 16, 0); - if (bd->compressed) - { - bitmap_decompress(bd->bitmapDataStream, (tui8*)dst_data, bd->width, - bd->height, bd->bitmapLength, server_bpp, server_bpp); + bi = mod->brush_cache + idx; + mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, + 3, bi->b8x8); } else - { /* bitmap is upside down */ - src = (char*)(bd->bitmapDataStream); - dst = dst_data + bd->height * line_bytes; - for (j = 0; j < bd->height; j++) - { - dst -= line_bytes; - g_memcpy(dst, src, line_bytes); - src += line_bytes; - } - } - dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, - bd->width, bd->height, mod->colormap); - mod->server_paint_rect(mod, bd->destLeft, bd->destTop, cx, cy, - dst_data1, bd->width, bd->height, 0, 0); - if (dst_data1 != dst_data) { - g_free(dst_data1); + mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, + patblt->brush.style, + (char *)(patblt->brush.p8x8)); } - g_free(dst_data); - } + + mod->server_fill_rect(mod, patblt->nLeftRect, patblt->nTopRect, + patblt->nWidth, patblt->nHeight); + mod->server_set_opcode(mod, 0xcc); + mod->server_set_mixmode(mod, 0); + } /******************************************************************************/ static void DEFAULT_CC -lfreerdp_dst_blt(rdpContext* context, DSTBLT_ORDER* dstblt) +lfreerdp_scr_blt(rdpContext *context, SCRBLT_ORDER *scrblt) { - struct mod* mod; + struct mod *mod; - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_dst_blt:")); - mod->server_set_opcode(mod, dstblt->bRop); - mod->server_fill_rect(mod, dstblt->nLeftRect, dstblt->nTopRect, - dstblt->nWidth, dstblt->nHeight); - mod->server_set_opcode(mod, 0xcc); + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_scr_blt:")); + mod->server_set_opcode(mod, scrblt->bRop); + mod->server_screen_blt(mod, scrblt->nLeftRect, scrblt->nTopRect, + scrblt->nWidth, scrblt->nHeight, + scrblt->nXSrc, scrblt->nYSrc); + mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC -lfreerdp_pat_blt(rdpContext* context, PATBLT_ORDER* patblt) +lfreerdp_opaque_rect(rdpContext *context, OPAQUE_RECT_ORDER *opaque_rect) { - struct mod* mod; - int idx; - int fgcolor; - int bgcolor; - int server_bpp; - int client_bpp; - struct brush_item* bi; + struct mod *mod; + int server_bpp; + int client_bpp; + int fgcolor; - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_pat_blt:")); + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_opaque_rect:")); + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + fgcolor = convert_color(server_bpp, client_bpp, + opaque_rect->color, mod->colormap); + mod->server_set_fgcolor(mod, fgcolor); + mod->server_fill_rect(mod, opaque_rect->nLeftRect, opaque_rect->nTopRect, + opaque_rect->nWidth, opaque_rect->nHeight); +} - server_bpp = mod->inst->settings->color_depth; - client_bpp = mod->bpp; - LLOGLN(0, ("lfreerdp_pat_blt: bpp %d %d", server_bpp, client_bpp)); +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_mem_blt(rdpContext *context, MEMBLT_ORDER *memblt) +{ + int id; + int idx; + struct mod *mod; + struct bitmap_item *bi; - fgcolor = convert_color(server_bpp, client_bpp, - patblt->foreColor, mod->colormap); - bgcolor = convert_color(server_bpp, client_bpp, - patblt->backColor, mod->colormap); + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_mem_blt: cacheId %d cacheIndex %d", + memblt->cacheId, memblt->cacheIndex)); - mod->server_set_mixmode(mod, 1); - mod->server_set_opcode(mod, patblt->bRop); - mod->server_set_fgcolor(mod, fgcolor); - mod->server_set_bgcolor(mod, bgcolor); + id = memblt->cacheId; + idx = memblt->cacheIndex; - if (patblt->brush.style & 0x80) - { - idx = patblt->brush.hatch; - if ((idx < 0) || (idx >= 64)) + if (idx == 32767) /* BITMAPCACHE_WAITING_LIST_INDEX */ { - LLOGLN(0, ("lfreerdp_pat_blt: error")); - return; + idx = 4096 - 1; } - bi = mod->brush_cache + idx; - mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, - 3, bi->b8x8); - } - else - { - mod->server_set_brush(mod, patblt->brush.x, patblt->brush.y, - patblt->brush.style, - (char*)(patblt->brush.p8x8)); - } - mod->server_fill_rect(mod, patblt->nLeftRect, patblt->nTopRect, - patblt->nWidth, patblt->nHeight); - mod->server_set_opcode(mod, 0xcc); - mod->server_set_mixmode(mod, 0); + + if ((id < 0) || (id >= 4)) + { + LLOGLN(0, ("lfreerdp_mem_blt: bad id [%d]", id)); + return; + } + + if ((idx < 0) || (idx >= 4096)) + { + LLOGLN(0, ("lfreerdp_mem_blt: bad idx [%d]", idx)); + return; + } + + bi = &(mod->bitmap_cache[id][idx]); + + mod->server_set_opcode(mod, memblt->bRop); + mod->server_paint_rect(mod, memblt->nLeftRect, memblt->nTopRect, + memblt->nWidth, memblt->nHeight, + bi->data, bi->width, bi->height, + memblt->nXSrc, memblt->nYSrc); + mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC -lfreerdp_scr_blt(rdpContext* context, SCRBLT_ORDER* scrblt) +lfreerdp_glyph_index(rdpContext *context, GLYPH_INDEX_ORDER *glyph_index) { - struct mod* mod; + struct mod *mod; + int server_bpp; + int client_bpp; + int fgcolor; + int bgcolor; - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_scr_blt:")); - mod->server_set_opcode(mod, scrblt->bRop); - mod->server_screen_blt(mod, scrblt->nLeftRect, scrblt->nTopRect, - scrblt->nWidth, scrblt->nHeight, - scrblt->nXSrc, scrblt->nYSrc); - mod->server_set_opcode(mod, 0xcc); + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_glyph_index:")); + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + fgcolor = convert_color(server_bpp, client_bpp, + glyph_index->foreColor, mod->colormap); + bgcolor = convert_color(server_bpp, client_bpp, + glyph_index->backColor, mod->colormap); + mod->server_set_bgcolor(mod, fgcolor); + mod->server_set_fgcolor(mod, bgcolor); + mod->server_draw_text(mod, glyph_index->cacheId, glyph_index->flAccel, + glyph_index->fOpRedundant, + glyph_index->bkLeft, glyph_index->bkTop, + glyph_index->bkRight, glyph_index->bkBottom, + glyph_index->opLeft, glyph_index->opTop, + glyph_index->opRight, glyph_index->opBottom, + glyph_index->x, glyph_index->y, + (char *)(glyph_index->data), glyph_index->cbData); } /******************************************************************************/ static void DEFAULT_CC -lfreerdp_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) +lfreerdp_line_to(rdpContext *context, LINE_TO_ORDER *line_to) { - struct mod* mod; - int server_bpp; - int client_bpp; - int fgcolor; + struct mod *mod; + int server_bpp; + int client_bpp; + int fgcolor; + int bgcolor; - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_opaque_rect:")); - server_bpp = mod->inst->settings->color_depth; - client_bpp = mod->bpp; - fgcolor = convert_color(server_bpp, client_bpp, - opaque_rect->color, mod->colormap); - mod->server_set_fgcolor(mod, fgcolor); - mod->server_fill_rect(mod, opaque_rect->nLeftRect, opaque_rect->nTopRect, - opaque_rect->nWidth, opaque_rect->nHeight); + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_line_to:")); + mod->server_set_opcode(mod, line_to->bRop2); + server_bpp = mod->inst->settings->color_depth; + client_bpp = mod->bpp; + fgcolor = convert_color(server_bpp, client_bpp, + line_to->penColor, mod->colormap); + bgcolor = convert_color(server_bpp, client_bpp, + line_to->backColor, mod->colormap); + mod->server_set_fgcolor(mod, fgcolor); + mod->server_set_bgcolor(mod, bgcolor); + mod->server_set_pen(mod, line_to->penStyle, line_to->penWidth); + mod->server_draw_line(mod, line_to->nXStart, line_to->nYStart, + line_to->nXEnd, line_to->nYEnd); + mod->server_set_opcode(mod, 0xcc); } /******************************************************************************/ static void DEFAULT_CC -lfreerdp_mem_blt(rdpContext* context, MEMBLT_ORDER* memblt) +lfreerdp_cache_bitmap(rdpContext *context, CACHE_BITMAP_ORDER *cache_bitmap_order) { - int id; - int idx; - struct mod* mod; - struct bitmap_item* bi; - - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_mem_blt: cacheId %d cacheIndex %d", - memblt->cacheId, memblt->cacheIndex)); - - id = memblt->cacheId; - idx = memblt->cacheIndex; - - if (idx == 32767) /* BITMAPCACHE_WAITING_LIST_INDEX */ - { - idx = 4096 - 1; - } - - if ((id < 0) || (id >= 4)) - { - LLOGLN(0, ("lfreerdp_mem_blt: bad id [%d]", id)); - return; - } - if ((idx < 0) || (idx >= 4096)) - { - LLOGLN(0, ("lfreerdp_mem_blt: bad idx [%d]", idx)); - return; - } - - bi = &(mod->bitmap_cache[id][idx]); - - mod->server_set_opcode(mod, memblt->bRop); - mod->server_paint_rect(mod, memblt->nLeftRect, memblt->nTopRect, - memblt->nWidth, memblt->nHeight, - bi->data, bi->width, bi->height, - memblt->nXSrc, memblt->nYSrc); - mod->server_set_opcode(mod, 0xcc); - -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyph_index) -{ - struct mod* mod; - int server_bpp; - int client_bpp; - int fgcolor; - int bgcolor; - - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_glyph_index:")); - server_bpp = mod->inst->settings->color_depth; - client_bpp = mod->bpp; - fgcolor = convert_color(server_bpp, client_bpp, - glyph_index->foreColor, mod->colormap); - bgcolor = convert_color(server_bpp, client_bpp, - glyph_index->backColor, mod->colormap); - mod->server_set_bgcolor(mod, fgcolor); - mod->server_set_fgcolor(mod, bgcolor); - mod->server_draw_text(mod, glyph_index->cacheId, glyph_index->flAccel, - glyph_index->fOpRedundant, - glyph_index->bkLeft, glyph_index->bkTop, - glyph_index->bkRight, glyph_index->bkBottom, - glyph_index->opLeft, glyph_index->opTop, - glyph_index->opRight, glyph_index->opBottom, - glyph_index->x, glyph_index->y, - (char*)(glyph_index->data), glyph_index->cbData); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_line_to(rdpContext* context, LINE_TO_ORDER* line_to) -{ - struct mod* mod; - int server_bpp; - int client_bpp; - int fgcolor; - int bgcolor; - - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_line_to:")); - mod->server_set_opcode(mod, line_to->bRop2); - server_bpp = mod->inst->settings->color_depth; - client_bpp = mod->bpp; - fgcolor = convert_color(server_bpp, client_bpp, - line_to->penColor, mod->colormap); - bgcolor = convert_color(server_bpp, client_bpp, - line_to->backColor, mod->colormap); - mod->server_set_fgcolor(mod, fgcolor); - mod->server_set_bgcolor(mod, bgcolor); - mod->server_set_pen(mod, line_to->penStyle, line_to->penWidth); - mod->server_draw_line(mod, line_to->nXStart, line_to->nYStart, - line_to->nXEnd, line_to->nYEnd); - mod->server_set_opcode(mod, 0xcc); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* cache_bitmap_order) -{ - LLOGLN(10, ("lfreerdp_cache_bitmap:")); + LLOGLN(10, ("lfreerdp_cache_bitmap:")); } /******************************************************************************/ /* Turn the bitmap upside down*/ static void DEFAULT_CC -lfreerdp_upsidedown(uint8* destination, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2_order, int server_Bpp) +lfreerdp_upsidedown(uint8 *destination, CACHE_BITMAP_V2_ORDER *cache_bitmap_v2_order, int server_Bpp) { - tui8* src; - tui8* dst; - int line_bytes; - int j; + tui8 *src; + tui8 *dst; + int line_bytes; + int j; - if (destination == NULL) - { - LLOGLN(0, ("lfreerdp_upsidedown: destination pointer is NULL !!!")); - return; - } - line_bytes = server_Bpp * cache_bitmap_v2_order->bitmapWidth; - src = cache_bitmap_v2_order->bitmapDataStream; - dst = destination + ((cache_bitmap_v2_order->bitmapHeight) * line_bytes); - for (j = 0; j < cache_bitmap_v2_order->bitmapHeight; j++) - { - dst -= line_bytes; - g_memcpy(dst, src, line_bytes); - src += line_bytes; - } -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_cache_bitmapV2(rdpContext* context, - CACHE_BITMAP_V2_ORDER* cache_bitmap_v2_order) -{ - char* dst_data; - char* dst_data1; - int bytes; - int width; - int height; - int id; - int idx; - int flags; - int server_bpp; - int server_Bpp; - int client_bpp; - struct mod* mod; - - LLOGLN(10, ("lfreerdp_cache_bitmapV2: %d %d 0x%8.8x compressed %d", - cache_bitmap_v2_order->cacheId, - cache_bitmap_v2_order->cacheIndex, - cache_bitmap_v2_order->flags, - cache_bitmap_v2_order->compressed)); - - mod = ((struct mod_context*)context)->modi; - id = cache_bitmap_v2_order->cacheId; - idx = cache_bitmap_v2_order->cacheIndex; - flags = cache_bitmap_v2_order->flags; - if (flags & 0x10) /* CBR2_DO_NOT_CACHE */ - { - idx = 4096 - 1; - } - if ((id < 0) || (id >= 4)) - { - LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad id [%d]", id)); - return; - } - if ((idx < 0) || (idx >= 4096)) - { - LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad idx [%d]", idx)); - return; - } - - server_bpp = mod->inst->settings->color_depth; - server_Bpp = (server_bpp + 7) / 8; - client_bpp = mod->bpp; - - width = cache_bitmap_v2_order->bitmapWidth; - height = cache_bitmap_v2_order->bitmapHeight; - bytes = width * height * server_Bpp + 16; - dst_data = (char*)g_malloc(bytes, 0); - if (cache_bitmap_v2_order->compressed) - { - bitmap_decompress(cache_bitmap_v2_order->bitmapDataStream, - (tui8*)dst_data, width, height, - cache_bitmap_v2_order->bitmapLength, - server_bpp, server_bpp); - } - else - { - /* Uncompressed bitmaps are upside down */ - lfreerdp_upsidedown((tui8*)dst_data, cache_bitmap_v2_order, server_Bpp); - LLOGLN(10, ("lfreerdp_cache_bitmapV2: upside down progressed")); - } - dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, - width, height, mod->colormap); - g_free(mod->bitmap_cache[id][idx].data); - mod->bitmap_cache[id][idx].width = width; - mod->bitmap_cache[id][idx].height = height; - mod->bitmap_cache[id][idx].data = dst_data1; - if (dst_data != dst_data1) - { - g_free(dst_data); - } -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cache_glyph_order) -{ - int index; - GLYPH_DATA* gd; - struct mod* mod; - - mod = ((struct mod_context*)context)->modi; - LLOGLN(10, ("lfreerdp_cache_glyph: %d", cache_glyph_order->cGlyphs)); - for (index = 0; index < cache_glyph_order->cGlyphs; index++) - { - gd = cache_glyph_order->glyphData[index]; - LLOGLN(10, (" %d %d %d %d %d", gd->cacheIndex, gd->x, gd->y, - gd->cx, gd->cy)); - mod->server_add_char(mod, cache_glyph_order->cacheId, gd->cacheIndex, - gd->x, gd->y, gd->cx, gd->cy, (char*)(gd->aj)); - xfree(gd->aj); - gd->aj = 0; - xfree(gd); - cache_glyph_order->glyphData[index] = 0; - } - xfree(cache_glyph_order->unicodeCharacters); - cache_glyph_order->unicodeCharacters = 0; -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cache_brush_order) -{ - int idx; - int bytes; - int bpp; - int cx; - int cy; - struct mod* mod; - - mod = ((struct mod_context*)context)->modi; - bpp = cache_brush_order->bpp; - cx = cache_brush_order->cx; - cy = cache_brush_order->cy; - idx = cache_brush_order->index; - bytes = cache_brush_order->length; - LLOGLN(10, ("lfreerdp_cache_brush: bpp %d cx %d cy %d idx %d bytes %d", - bpp, cx, cy, idx, bytes)); - if ((idx < 0) || (idx >= 64)) - { - LLOGLN(0, ("lfreerdp_cache_brush: error idx %d", idx)); - return; - } - if ((bpp != 1) || (cx != 8) || (cy != 8)) - { - LLOGLN(0, ("lfreerdp_cache_brush: error unsupported brush " - "bpp %d cx %d cy %d", bpp, cx, cy)); - return; - } - mod->brush_cache[idx].bpp = bpp; - mod->brush_cache[idx].width = cx; - mod->brush_cache[idx].height = cy; - mod->brush_cache[idx].data = mod->brush_cache[idx].b8x8; - if (bytes > 8) - { - bytes = 8; - } - g_memset(mod->brush_cache[idx].data, 0, 8); - if (bytes > 0) - { - if (bytes > 8) + if (destination == NULL) { - LLOGLN(0, ("lfreerdp_cache_brush: bytes to big %d", bytes)); - bytes = 8; + LLOGLN(0, ("lfreerdp_upsidedown: destination pointer is NULL !!!")); + return; } - g_memcpy(mod->brush_cache[idx].data, cache_brush_order->data, bytes); - } - LLOGLN(10, ("lfreerdp_cache_brush: out bpp %d cx %d cy %d idx %d bytes %d", - bpp, cx, cy, idx, bytes)); - xfree(cache_brush_order->data); - cache_brush_order->data = 0; + line_bytes = server_Bpp * cache_bitmap_v2_order->bitmapWidth; + src = cache_bitmap_v2_order->bitmapDataStream; + dst = destination + ((cache_bitmap_v2_order->bitmapHeight) * line_bytes); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_position(rdpContext* context, - POINTER_POSITION_UPDATE* pointer_position) -{ - LLOGLN(0, ("lfreerdp_pointer_position:")); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_system(rdpContext* context, - POINTER_SYSTEM_UPDATE* pointer_system) -{ - LLOGLN(0, ("lfreerdp_pointer_system: - no code here")); -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_color(rdpContext* context, - POINTER_COLOR_UPDATE* pointer_color) -{ - LLOGLN(0, ("lfreerdp_pointer_color:")); -} - -/******************************************************************************/ -static int APP_CC -lfreerdp_get_pixel(void* bits, int width, int height, int bpp, - int delta, int x, int y) -{ - int start; - int shift; - int pixel; - tui8* src8; - - if (bpp == 1) - { - src8 = (tui8*)bits; - start = (y * delta) + x / 8; - shift = x % 8; - pixel = (src8[start] & (0x80 >> shift)) != 0; - return pixel ? 0xffffff : 0; - } - else - { - LLOGLN(0, ("lfreerdp_get_pixel: unknown bpp %d", bpp)); - } - return 0; -} - -/******************************************************************************/ -static int APP_CC -lfreerdp_set_pixel(int pixel, void* bits, int width, int height, int bpp, - int delta, int x, int y) -{ - tui8* dst8; - int start; - int shift; - - if (bpp == 1) - { - dst8 = (tui8*)bits; - start = (y * delta) + x / 8; - shift = x % 8; - if (pixel) + for (j = 0; j < cache_bitmap_v2_order->bitmapHeight; j++) { - dst8[start] = dst8[start] | (0x80 >> shift); + dst -= line_bytes; + g_memcpy(dst, src, line_bytes); + src += line_bytes; + } +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_cache_bitmapV2(rdpContext *context, + CACHE_BITMAP_V2_ORDER *cache_bitmap_v2_order) +{ + char *dst_data; + char *dst_data1; + int bytes; + int width; + int height; + int id; + int idx; + int flags; + int server_bpp; + int server_Bpp; + int client_bpp; + struct mod *mod; + + LLOGLN(10, ("lfreerdp_cache_bitmapV2: %d %d 0x%8.8x compressed %d", + cache_bitmap_v2_order->cacheId, + cache_bitmap_v2_order->cacheIndex, + cache_bitmap_v2_order->flags, + cache_bitmap_v2_order->compressed)); + + mod = ((struct mod_context *)context)->modi; + id = cache_bitmap_v2_order->cacheId; + idx = cache_bitmap_v2_order->cacheIndex; + flags = cache_bitmap_v2_order->flags; + + if (flags & 0x10) /* CBR2_DO_NOT_CACHE */ + { + idx = 4096 - 1; + } + + if ((id < 0) || (id >= 4)) + { + LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad id [%d]", id)); + return; + } + + if ((idx < 0) || (idx >= 4096)) + { + LLOGLN(0, ("lfreerdp_cache_bitmapV2: bad idx [%d]", idx)); + return; + } + + server_bpp = mod->inst->settings->color_depth; + server_Bpp = (server_bpp + 7) / 8; + client_bpp = mod->bpp; + + width = cache_bitmap_v2_order->bitmapWidth; + height = cache_bitmap_v2_order->bitmapHeight; + bytes = width * height * server_Bpp + 16; + dst_data = (char *)g_malloc(bytes, 0); + + if (cache_bitmap_v2_order->compressed) + { + bitmap_decompress(cache_bitmap_v2_order->bitmapDataStream, + (tui8 *)dst_data, width, height, + cache_bitmap_v2_order->bitmapLength, + server_bpp, server_bpp); } else { - dst8[start] = dst8[start] & ~(0x80 >> shift); + /* Uncompressed bitmaps are upside down */ + lfreerdp_upsidedown((tui8 *)dst_data, cache_bitmap_v2_order, server_Bpp); + LLOGLN(10, ("lfreerdp_cache_bitmapV2: upside down progressed")); } - } - else if (bpp == 24) - { - dst8 = (tui8*)bits; - dst8 += y * delta + x * 3; - dst8[0] = (pixel >> 0) & 0xff; - dst8[1] = (pixel >> 8) & 0xff; - dst8[2] = (pixel >> 16) & 0xff; - } - else - { - LLOGLN(0, ("lfreerdp_set_pixel: unknown bpp %d", bpp)); - } - return 0; + + dst_data1 = convert_bitmap(server_bpp, client_bpp, dst_data, + width, height, mod->colormap); + g_free(mod->bitmap_cache[id][idx].data); + mod->bitmap_cache[id][idx].width = width; + mod->bitmap_cache[id][idx].height = height; + mod->bitmap_cache[id][idx].data = dst_data1; + + if (dst_data != dst_data1) + { + g_free(dst_data); + } +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_cache_glyph(rdpContext *context, CACHE_GLYPH_ORDER *cache_glyph_order) +{ + int index; + GLYPH_DATA *gd; + struct mod *mod; + + mod = ((struct mod_context *)context)->modi; + LLOGLN(10, ("lfreerdp_cache_glyph: %d", cache_glyph_order->cGlyphs)); + + for (index = 0; index < cache_glyph_order->cGlyphs; index++) + { + gd = cache_glyph_order->glyphData[index]; + LLOGLN(10, (" %d %d %d %d %d", gd->cacheIndex, gd->x, gd->y, + gd->cx, gd->cy)); + mod->server_add_char(mod, cache_glyph_order->cacheId, gd->cacheIndex, + gd->x, gd->y, gd->cx, gd->cy, (char *)(gd->aj)); + xfree(gd->aj); + gd->aj = 0; + xfree(gd); + cache_glyph_order->glyphData[index] = 0; + } + + xfree(cache_glyph_order->unicodeCharacters); + cache_glyph_order->unicodeCharacters = 0; +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_cache_brush(rdpContext *context, CACHE_BRUSH_ORDER *cache_brush_order) +{ + int idx; + int bytes; + int bpp; + int cx; + int cy; + struct mod *mod; + + mod = ((struct mod_context *)context)->modi; + bpp = cache_brush_order->bpp; + cx = cache_brush_order->cx; + cy = cache_brush_order->cy; + idx = cache_brush_order->index; + bytes = cache_brush_order->length; + LLOGLN(10, ("lfreerdp_cache_brush: bpp %d cx %d cy %d idx %d bytes %d", + bpp, cx, cy, idx, bytes)); + + if ((idx < 0) || (idx >= 64)) + { + LLOGLN(0, ("lfreerdp_cache_brush: error idx %d", idx)); + return; + } + + if ((bpp != 1) || (cx != 8) || (cy != 8)) + { + LLOGLN(0, ("lfreerdp_cache_brush: error unsupported brush " + "bpp %d cx %d cy %d", bpp, cx, cy)); + return; + } + + mod->brush_cache[idx].bpp = bpp; + mod->brush_cache[idx].width = cx; + mod->brush_cache[idx].height = cy; + mod->brush_cache[idx].data = mod->brush_cache[idx].b8x8; + + if (bytes > 8) + { + bytes = 8; + } + + g_memset(mod->brush_cache[idx].data, 0, 8); + + if (bytes > 0) + { + if (bytes > 8) + { + LLOGLN(0, ("lfreerdp_cache_brush: bytes to big %d", bytes)); + bytes = 8; + } + + g_memcpy(mod->brush_cache[idx].data, cache_brush_order->data, bytes); + } + + LLOGLN(10, ("lfreerdp_cache_brush: out bpp %d cx %d cy %d idx %d bytes %d", + bpp, cx, cy, idx, bytes)); + + xfree(cache_brush_order->data); + cache_brush_order->data = 0; + +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_position(rdpContext *context, + POINTER_POSITION_UPDATE *pointer_position) +{ + LLOGLN(0, ("lfreerdp_pointer_position:")); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_system(rdpContext *context, + POINTER_SYSTEM_UPDATE *pointer_system) +{ + LLOGLN(0, ("lfreerdp_pointer_system: - no code here")); +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_color(rdpContext *context, + POINTER_COLOR_UPDATE *pointer_color) +{ + LLOGLN(0, ("lfreerdp_pointer_color:")); } /******************************************************************************/ static int APP_CC -lfreerdp_convert_color_image(void* dst, int dst_width, int dst_height, +lfreerdp_get_pixel(void *bits, int width, int height, int bpp, + int delta, int x, int y) +{ + int start; + int shift; + int pixel; + tui8 *src8; + + if (bpp == 1) + { + src8 = (tui8 *)bits; + start = (y * delta) + x / 8; + shift = x % 8; + pixel = (src8[start] & (0x80 >> shift)) != 0; + return pixel ? 0xffffff : 0; + } + else + { + LLOGLN(0, ("lfreerdp_get_pixel: unknown bpp %d", bpp)); + } + + return 0; +} + +/******************************************************************************/ +static int APP_CC +lfreerdp_set_pixel(int pixel, void *bits, int width, int height, int bpp, + int delta, int x, int y) +{ + tui8 *dst8; + int start; + int shift; + + if (bpp == 1) + { + dst8 = (tui8 *)bits; + start = (y * delta) + x / 8; + shift = x % 8; + + if (pixel) + { + dst8[start] = dst8[start] | (0x80 >> shift); + } + else + { + dst8[start] = dst8[start] & ~(0x80 >> shift); + } + } + else if (bpp == 24) + { + dst8 = (tui8 *)bits; + dst8 += y * delta + x * 3; + dst8[0] = (pixel >> 0) & 0xff; + dst8[1] = (pixel >> 8) & 0xff; + dst8[2] = (pixel >> 16) & 0xff; + } + else + { + LLOGLN(0, ("lfreerdp_set_pixel: unknown bpp %d", bpp)); + } + + return 0; +} + +/******************************************************************************/ +static int APP_CC +lfreerdp_convert_color_image(void *dst, int dst_width, int dst_height, int dst_bpp, int dst_delta, - void* src, int src_width, int src_height, + void *src, int src_width, int src_height, int src_bpp, int src_delta) { - int i; - int j; - int pixel; + int i; + int j; + int pixel; - for (j = 0; j < dst_height; j++) - { - for (i = 0; i < dst_width; i++) + for (j = 0; j < dst_height; j++) { - pixel = lfreerdp_get_pixel(src, src_width, src_height, src_bpp, - src_delta, i, j); - lfreerdp_set_pixel(pixel, dst, dst_width, dst_height, dst_bpp, - dst_delta, i, j); + for (i = 0; i < dst_width; i++) + { + pixel = lfreerdp_get_pixel(src, src_width, src_height, src_bpp, + src_delta, i, j); + lfreerdp_set_pixel(pixel, dst, dst_width, dst_height, dst_bpp, + dst_delta, i, j); + } } - } - return 0; + + return 0; } /******************************************************************************/ static void DEFAULT_CC -lfreerdp_pointer_new(rdpContext* context, - POINTER_NEW_UPDATE* pointer_new) +lfreerdp_pointer_new(rdpContext *context, + POINTER_NEW_UPDATE *pointer_new) { - struct mod* mod; - int index; - tui8* dst; - tui8* src; + struct mod *mod; + int index; + tui8 *dst; + tui8 *src; - mod = ((struct mod_context*)context)->modi; - LLOGLN(0, ("lfreerdp_pointer_new:")); - LLOGLN(0, (" bpp %d", pointer_new->xorBpp)); - LLOGLN(0, (" width %d height %d", pointer_new->colorPtrAttr.width, - pointer_new->colorPtrAttr.height)); + mod = ((struct mod_context *)context)->modi; + LLOGLN(0, ("lfreerdp_pointer_new:")); + LLOGLN(0, (" bpp %d", pointer_new->xorBpp)); + LLOGLN(0, (" width %d height %d", pointer_new->colorPtrAttr.width, + pointer_new->colorPtrAttr.height)); - LLOGLN(0, (" lengthXorMask %d lengthAndMask %d", - pointer_new->colorPtrAttr.lengthXorMask, - pointer_new->colorPtrAttr.lengthAndMask)); + LLOGLN(0, (" lengthXorMask %d lengthAndMask %d", + pointer_new->colorPtrAttr.lengthXorMask, + pointer_new->colorPtrAttr.lengthAndMask)); - index = pointer_new->colorPtrAttr.cacheIndex; - if (pointer_new->xorBpp == 1 && - pointer_new->colorPtrAttr.width == 32 && - pointer_new->colorPtrAttr.height == 32 && - index < 32) - { - mod->pointer_cache[index].hotx = pointer_new->colorPtrAttr.xPos; - mod->pointer_cache[index].hoty = pointer_new->colorPtrAttr.yPos; + index = pointer_new->colorPtrAttr.cacheIndex; - dst = (tui8*)(mod->pointer_cache[index].data); - dst += 32 * 32 * 3 - 32 * 3; - src = pointer_new->colorPtrAttr.xorMaskData; - lfreerdp_convert_color_image(dst, 32, 32, 24, 32 * -3, - src, 32, 32, 1, 32 / 8); + if (pointer_new->xorBpp == 1 && + pointer_new->colorPtrAttr.width == 32 && + pointer_new->colorPtrAttr.height == 32 && + index < 32) + { + mod->pointer_cache[index].hotx = pointer_new->colorPtrAttr.xPos; + mod->pointer_cache[index].hoty = pointer_new->colorPtrAttr.yPos; - dst = (tui8*)(mod->pointer_cache[index].mask); - dst +=( 32 * 32 / 8) - (32 / 8); - src = pointer_new->colorPtrAttr.andMaskData; - lfreerdp_convert_color_image(dst, 32, 32, 1, 32 / -8, - src, 32, 32, 1, 32 / 8); + dst = (tui8 *)(mod->pointer_cache[index].data); + dst += 32 * 32 * 3 - 32 * 3; + src = pointer_new->colorPtrAttr.xorMaskData; + lfreerdp_convert_color_image(dst, 32, 32, 24, 32 * -3, + src, 32, 32, 1, 32 / 8); - //memcpy(mod->pointer_cache[index].mask, - // pointer_new->colorPtrAttr.andMaskData, 32 * 32 / 8); + dst = (tui8 *)(mod->pointer_cache[index].mask); + dst += ( 32 * 32 / 8) - (32 / 8); + src = pointer_new->colorPtrAttr.andMaskData; + lfreerdp_convert_color_image(dst, 32, 32, 1, 32 / -8, + src, 32, 32, 1, 32 / 8); + //memcpy(mod->pointer_cache[index].mask, + // pointer_new->colorPtrAttr.andMaskData, 32 * 32 / 8); + + mod->server_set_cursor(mod, mod->pointer_cache[index].hotx, + mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, + mod->pointer_cache[index].mask); + } + else + { + LLOGLN(0, ("lfreerdp_pointer_new: error bpp %d width %d height %d", + pointer_new->xorBpp, pointer_new->colorPtrAttr.width, + pointer_new->colorPtrAttr.height)); + } + + xfree(pointer_new->colorPtrAttr.xorMaskData); + pointer_new->colorPtrAttr.xorMaskData = 0; + xfree(pointer_new->colorPtrAttr.andMaskData); + pointer_new->colorPtrAttr.andMaskData = 0; + +} + +/******************************************************************************/ +static void DEFAULT_CC +lfreerdp_pointer_cached(rdpContext *context, + POINTER_CACHED_UPDATE *pointer_cached) +{ + struct mod *mod; + int index; + + LLOGLN(10, ("lfreerdp_pointer_cached:")); + mod = ((struct mod_context *)context)->modi; + index = pointer_cached->cacheIndex; mod->server_set_cursor(mod, mod->pointer_cache[index].hotx, - mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, - mod->pointer_cache[index].mask); - } - else - { - LLOGLN(0, ("lfreerdp_pointer_new: error bpp %d width %d height %d", - pointer_new->xorBpp, pointer_new->colorPtrAttr.width, - pointer_new->colorPtrAttr.height)); - } - - xfree(pointer_new->colorPtrAttr.xorMaskData); - pointer_new->colorPtrAttr.xorMaskData = 0; - xfree(pointer_new->colorPtrAttr.andMaskData); - pointer_new->colorPtrAttr.andMaskData = 0; - -} - -/******************************************************************************/ -static void DEFAULT_CC -lfreerdp_pointer_cached(rdpContext* context, - POINTER_CACHED_UPDATE* pointer_cached) -{ - struct mod* mod; - int index; - - LLOGLN(10, ("lfreerdp_pointer_cached:")); - mod = ((struct mod_context*)context)->modi; - index = pointer_cached->cacheIndex; - mod->server_set_cursor(mod, mod->pointer_cache[index].hotx, - mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, - mod->pointer_cache[index].mask); + mod->pointer_cache[index].hoty, mod->pointer_cache[index].data, + mod->pointer_cache[index].mask); } /******************************************************************************/ static boolean DEFAULT_CC -lfreerdp_pre_connect(freerdp* instance) +lfreerdp_pre_connect(freerdp *instance) { - struct mod* mod; - int index; - int error; - int num_chans; - int ch_flags; - char ch_name[256]; - char* dst_ch_name; + struct mod *mod; + int index; + int error; + int num_chans; + int ch_flags; + char ch_name[256]; + char *dst_ch_name; - LLOGLN(0, ("lfreerdp_pre_connect:")); - mod = ((struct mod_context*)(instance->context))->modi; - num_chans = 0; - index = 0; - error = mod->server_query_channel(mod, index, ch_name, &ch_flags); - while (error == 0) - { - num_chans++; - LLOGLN(10, ("lfreerdp_pre_connect: got channel [%s], flags [0x%8.8x]", - ch_name, ch_flags)); - dst_ch_name = instance->settings->channels[index].name; - g_memset(dst_ch_name, 0, 8); - g_snprintf(dst_ch_name, 8, "%s", ch_name); - instance->settings->channels[index].options = ch_flags; - index++; + LLOGLN(0, ("lfreerdp_pre_connect:")); + mod = ((struct mod_context *)(instance->context))->modi; + num_chans = 0; + index = 0; error = mod->server_query_channel(mod, index, ch_name, &ch_flags); - } - instance->settings->num_channels = num_chans; - instance->settings->offscreen_bitmap_cache = false; - - instance->settings->glyph_cache = true; - instance->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL; - instance->settings->order_support[NEG_GLYPH_INDEX_INDEX] = true; - instance->settings->order_support[NEG_FAST_GLYPH_INDEX] = false; - instance->settings->order_support[NEG_FAST_INDEX_INDEX] = false; - instance->settings->order_support[NEG_SCRBLT_INDEX] = true; - instance->settings->order_support[NEG_SAVEBITMAP_INDEX] = false; - - instance->settings->bitmap_cache = true; - instance->settings->order_support[NEG_MEMBLT_INDEX] = true; - instance->settings->order_support[NEG_MEMBLT_V2_INDEX] = true; - instance->settings->order_support[NEG_MEM3BLT_INDEX] = false; - instance->settings->order_support[NEG_MEM3BLT_V2_INDEX] = false; - instance->settings->bitmapCacheV2NumCells = 3; // 5; - instance->settings->bitmapCacheV2CellInfo[0].numEntries = 0x78; // 600; - instance->settings->bitmapCacheV2CellInfo[0].persistent = false; - instance->settings->bitmapCacheV2CellInfo[1].numEntries = 0x78; // 600; - instance->settings->bitmapCacheV2CellInfo[1].persistent = false; - instance->settings->bitmapCacheV2CellInfo[2].numEntries = 0x150; // 2048; - instance->settings->bitmapCacheV2CellInfo[2].persistent = false; - instance->settings->bitmapCacheV2CellInfo[3].numEntries = 0; // 4096; - instance->settings->bitmapCacheV2CellInfo[3].persistent = false; - instance->settings->bitmapCacheV2CellInfo[4].numEntries = 0; // 2048; - instance->settings->bitmapCacheV2CellInfo[4].persistent = false; - - instance->settings->order_support[NEG_MULTIDSTBLT_INDEX] = false; - instance->settings->order_support[NEG_MULTIPATBLT_INDEX] = false; - instance->settings->order_support[NEG_MULTISCRBLT_INDEX] = false; - instance->settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = false; - instance->settings->order_support[NEG_POLYLINE_INDEX] = false; - - instance->settings->username = g_strdup(mod->username); - instance->settings->password = g_strdup(mod->password); - - if (mod->client_info.rail_support_level > 0) - { - instance->settings->remote_app = true; - instance->settings->rail_langbar_supported = true; - instance->settings->workarea = true; - instance->settings->performance_flags = PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG; - } - - // here - //instance->settings->rdp_version = 4; - - instance->update->BeginPaint = lfreerdp_begin_paint; - instance->update->EndPaint = lfreerdp_end_paint; - instance->update->SetBounds = lfreerdp_set_bounds; - instance->update->BitmapUpdate = lfreerdp_bitmap_update; - - instance->update->primary->DstBlt = lfreerdp_dst_blt; - instance->update->primary->PatBlt = lfreerdp_pat_blt; - instance->update->primary->ScrBlt = lfreerdp_scr_blt; - instance->update->primary->OpaqueRect = lfreerdp_opaque_rect; - instance->update->primary->MemBlt = lfreerdp_mem_blt; - instance->update->primary->GlyphIndex = lfreerdp_glyph_index; - instance->update->primary->LineTo = lfreerdp_line_to; - - instance->update->secondary->CacheBitmap = lfreerdp_cache_bitmap; - instance->update->secondary->CacheBitmapV2 = lfreerdp_cache_bitmapV2; - instance->update->secondary->CacheGlyph = lfreerdp_cache_glyph; - instance->update->secondary->CacheBrush = lfreerdp_cache_brush; - - instance->update->pointer->PointerPosition = lfreerdp_pointer_position; - instance->update->pointer->PointerSystem = lfreerdp_pointer_system; - instance->update->pointer->PointerColor = lfreerdp_pointer_color; - instance->update->pointer->PointerNew = lfreerdp_pointer_new; - instance->update->pointer->PointerCached = lfreerdp_pointer_cached; - - if ((mod->username[0] != 0) && (mod->password[0] != 0)) - { - /* since we have username and password, we can try nla */ - instance->settings->nla_security = 1; - } - else - { - instance->settings->nla_security = 0; - } - - return true; -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowCreate(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, - WINDOW_STATE_ORDER* window_state) -{ - int index; - struct mod* mod; - struct rail_window_state_order wso; - UNICONV* uniconv; - - LLOGLN(0, ("llrail_WindowCreate:")); - uniconv = freerdp_uniconv_new(); - mod = ((struct mod_context*)context)->modi; - memset(&wso, 0, sizeof(wso)); - /* copy the window state order */ - wso.owner_window_id = window_state->ownerWindowId; - wso.style = window_state->style; - wso.extended_style = window_state->extendedStyle; - wso.show_state = window_state->showState; - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE) - { - wso.title_info = freerdp_uniconv_in(uniconv, - window_state->titleInfo.string, window_state->titleInfo.length); - } - LLOGLN(0, ("lrail_WindowCreate: %s", wso.title_info)); - wso.client_offset_x = window_state->clientOffsetX; - wso.client_offset_y = window_state->clientOffsetY; - wso.client_area_width = window_state->clientAreaWidth; - wso.client_area_height = window_state->clientAreaHeight; - wso.rp_content = window_state->RPContent; - wso.root_parent_handle = window_state->rootParentHandle; - wso.window_offset_x = window_state->windowOffsetX; - wso.window_offset_y = window_state->windowOffsetY; - wso.window_client_delta_x = window_state->windowClientDeltaX; - wso.window_client_delta_y = window_state->windowClientDeltaY; - wso.window_width = window_state->windowWidth; - wso.window_height = window_state->windowHeight; - wso.num_window_rects = window_state->numWindowRects; - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) - { - wso.window_rects = (struct rail_window_rect*) - g_malloc(sizeof(struct rail_window_rect) * wso.num_window_rects, 0); - for (index = 0; index < wso.num_window_rects; index++) + while (error == 0) { - wso.window_rects[index].left = window_state->windowRects[index].left; - wso.window_rects[index].top = window_state->windowRects[index].top; - wso.window_rects[index].right = window_state->windowRects[index].right; - wso.window_rects[index].bottom = window_state->windowRects[index].bottom; + num_chans++; + LLOGLN(10, ("lfreerdp_pre_connect: got channel [%s], flags [0x%8.8x]", + ch_name, ch_flags)); + dst_ch_name = instance->settings->channels[index].name; + g_memset(dst_ch_name, 0, 8); + g_snprintf(dst_ch_name, 8, "%s", ch_name); + instance->settings->channels[index].options = ch_flags; + index++; + error = mod->server_query_channel(mod, index, ch_name, &ch_flags); } - } - wso.visible_offset_x = window_state->visibleOffsetX; - wso.visible_offset_y = window_state->visibleOffsetY; - wso.num_visibility_rects = window_state->numVisibilityRects; - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) - { - wso.visibility_rects = (struct rail_window_rect*) - g_malloc(sizeof(struct rail_window_rect) * wso.num_visibility_rects, 0); - for (index = 0; index < wso.num_visibility_rects; index++) + + instance->settings->num_channels = num_chans; + + instance->settings->offscreen_bitmap_cache = false; + + instance->settings->glyph_cache = true; + instance->settings->glyphSupportLevel = GLYPH_SUPPORT_FULL; + instance->settings->order_support[NEG_GLYPH_INDEX_INDEX] = true; + instance->settings->order_support[NEG_FAST_GLYPH_INDEX] = false; + instance->settings->order_support[NEG_FAST_INDEX_INDEX] = false; + instance->settings->order_support[NEG_SCRBLT_INDEX] = true; + instance->settings->order_support[NEG_SAVEBITMAP_INDEX] = false; + + instance->settings->bitmap_cache = true; + instance->settings->order_support[NEG_MEMBLT_INDEX] = true; + instance->settings->order_support[NEG_MEMBLT_V2_INDEX] = true; + instance->settings->order_support[NEG_MEM3BLT_INDEX] = false; + instance->settings->order_support[NEG_MEM3BLT_V2_INDEX] = false; + instance->settings->bitmapCacheV2NumCells = 3; // 5; + instance->settings->bitmapCacheV2CellInfo[0].numEntries = 0x78; // 600; + instance->settings->bitmapCacheV2CellInfo[0].persistent = false; + instance->settings->bitmapCacheV2CellInfo[1].numEntries = 0x78; // 600; + instance->settings->bitmapCacheV2CellInfo[1].persistent = false; + instance->settings->bitmapCacheV2CellInfo[2].numEntries = 0x150; // 2048; + instance->settings->bitmapCacheV2CellInfo[2].persistent = false; + instance->settings->bitmapCacheV2CellInfo[3].numEntries = 0; // 4096; + instance->settings->bitmapCacheV2CellInfo[3].persistent = false; + instance->settings->bitmapCacheV2CellInfo[4].numEntries = 0; // 2048; + instance->settings->bitmapCacheV2CellInfo[4].persistent = false; + + instance->settings->order_support[NEG_MULTIDSTBLT_INDEX] = false; + instance->settings->order_support[NEG_MULTIPATBLT_INDEX] = false; + instance->settings->order_support[NEG_MULTISCRBLT_INDEX] = false; + instance->settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = false; + instance->settings->order_support[NEG_POLYLINE_INDEX] = false; + + instance->settings->username = g_strdup(mod->username); + instance->settings->password = g_strdup(mod->password); + + if (mod->client_info.rail_support_level > 0) { - wso.visibility_rects[index].left = window_state->visibilityRects[index].left; - wso.visibility_rects[index].top = window_state->visibilityRects[index].top; - wso.visibility_rects[index].right = window_state->visibilityRects[index].right; - wso.visibility_rects[index].bottom = window_state->visibilityRects[index].bottom; + instance->settings->remote_app = true; + instance->settings->rail_langbar_supported = true; + instance->settings->workarea = true; + instance->settings->performance_flags = PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG; } - } - mod->server_window_new_update(mod, orderInfo->windowId, &wso, - orderInfo->fieldFlags); + // here + //instance->settings->rdp_version = 4; - xfree(wso.title_info); - g_free(wso.window_rects); - g_free(wso.visibility_rects); - freerdp_uniconv_free(uniconv); -} + instance->update->BeginPaint = lfreerdp_begin_paint; + instance->update->EndPaint = lfreerdp_end_paint; + instance->update->SetBounds = lfreerdp_set_bounds; + instance->update->BitmapUpdate = lfreerdp_bitmap_update; -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowUpdate(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, - WINDOW_STATE_ORDER* window_state) -{ - LLOGLN(0, ("lrail_WindowUpdate:")); - lrail_WindowCreate(context, orderInfo, window_state); -} + instance->update->primary->DstBlt = lfreerdp_dst_blt; + instance->update->primary->PatBlt = lfreerdp_pat_blt; + instance->update->primary->ScrBlt = lfreerdp_scr_blt; + instance->update->primary->OpaqueRect = lfreerdp_opaque_rect; + instance->update->primary->MemBlt = lfreerdp_mem_blt; + instance->update->primary->GlyphIndex = lfreerdp_glyph_index; + instance->update->primary->LineTo = lfreerdp_line_to; -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowDelete(rdpContext* context, WINDOW_ORDER_INFO* orderInfo) -{ - struct mod* mod; + instance->update->secondary->CacheBitmap = lfreerdp_cache_bitmap; + instance->update->secondary->CacheBitmapV2 = lfreerdp_cache_bitmapV2; + instance->update->secondary->CacheGlyph = lfreerdp_cache_glyph; + instance->update->secondary->CacheBrush = lfreerdp_cache_brush; - LLOGLN(0, ("lrail_WindowDelete:")); - mod = ((struct mod_context*)context)->modi; - mod->server_window_delete(mod, orderInfo->windowId); -} + instance->update->pointer->PointerPosition = lfreerdp_pointer_position; + instance->update->pointer->PointerSystem = lfreerdp_pointer_system; + instance->update->pointer->PointerColor = lfreerdp_pointer_color; + instance->update->pointer->PointerNew = lfreerdp_pointer_new; + instance->update->pointer->PointerCached = lfreerdp_pointer_cached; -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowIcon(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, - WINDOW_ICON_ORDER* window_icon) -{ - struct mod* mod; - struct rail_icon_info rii; - - LLOGLN(0, ("lrail_WindowIcon:")); - mod = ((struct mod_context*)context)->modi; - memset(&rii, 0, sizeof(rii)); - rii.bpp = window_icon->iconInfo->bpp; - rii.width = window_icon->iconInfo->width; - rii.height = window_icon->iconInfo->height; - rii.cmap_bytes = window_icon->iconInfo->cbColorTable; - rii.mask_bytes = window_icon->iconInfo->cbBitsMask; - rii.data_bytes = window_icon->iconInfo->cbBitsColor; - rii.mask = (char*)(window_icon->iconInfo->bitsMask); - rii.cmap = (char*)(window_icon->iconInfo->colorTable); - rii.data = (char*)(window_icon->iconInfo->bitsColor); - mod->server_window_icon(mod, orderInfo->windowId, - window_icon->iconInfo->cacheEntry, - window_icon->iconInfo->cacheId, &rii, - orderInfo->fieldFlags); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_WindowCachedIcon(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, - WINDOW_CACHED_ICON_ORDER* window_cached_icon) -{ - struct mod* mod; - - LLOGLN(0, ("lrail_WindowCachedIcon:")); - mod = ((struct mod_context*)context)->modi; - mod->server_window_cached_icon(mod, orderInfo->windowId, - window_cached_icon->cachedIcon.cacheEntry, - window_cached_icon->cachedIcon.cacheId, - orderInfo->fieldFlags); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_NotifyIconCreate(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, - NOTIFY_ICON_STATE_ORDER* notify_icon_state) -{ - struct mod* mod; - struct rail_notify_state_order rnso; - UNICONV* uniconv; - - - LLOGLN(0, ("lrail_NotifyIconCreate:")); - uniconv = freerdp_uniconv_new(); - - mod = ((struct mod_context*)context)->modi; - - memset(&rnso, 0, sizeof(rnso)); - rnso.version = notify_icon_state->version; - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP) - { - rnso.tool_tip = freerdp_uniconv_in(uniconv, - notify_icon_state->toolTip.string, notify_icon_state->toolTip.length); - } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) - { - rnso.infotip.timeout = notify_icon_state->infoTip.timeout; - rnso.infotip.flags = notify_icon_state->infoTip.flags; - rnso.infotip.text = freerdp_uniconv_in(uniconv, - notify_icon_state->infoTip.text.string, - notify_icon_state->infoTip.text.length); - rnso.infotip.title = freerdp_uniconv_in(uniconv, - notify_icon_state->infoTip.title.string, - notify_icon_state->infoTip.title.length); - } - rnso.state = notify_icon_state->state; - rnso.icon_cache_entry = notify_icon_state->icon.cacheEntry; - rnso.icon_cache_id = notify_icon_state->icon.cacheId; - - rnso.icon_info.bpp = notify_icon_state->icon.bpp; - rnso.icon_info.width = notify_icon_state->icon.width; - rnso.icon_info.height = notify_icon_state->icon.height; - rnso.icon_info.cmap_bytes = notify_icon_state->icon.cbColorTable; - rnso.icon_info.mask_bytes = notify_icon_state->icon.cbBitsMask; - rnso.icon_info.data_bytes = notify_icon_state->icon.cbBitsColor; - rnso.icon_info.mask = (char*)(notify_icon_state->icon.bitsMask); - rnso.icon_info.cmap = (char*)(notify_icon_state->icon.colorTable); - rnso.icon_info.data = (char*)(notify_icon_state->icon.bitsColor); - - mod->server_notify_new_update(mod, orderInfo->windowId, - orderInfo->notifyIconId, - &rnso, orderInfo->fieldFlags); - - xfree(rnso.tool_tip); - xfree(rnso.infotip.text); - xfree(rnso.infotip.title); - freerdp_uniconv_free(uniconv); - -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_NotifyIconUpdate(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, - NOTIFY_ICON_STATE_ORDER* notify_icon_state) -{ - LLOGLN(0, ("lrail_NotifyIconUpdate:")); - lrail_NotifyIconCreate(context, orderInfo, notify_icon_state); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_NotifyIconDelete(rdpContext* context, WINDOW_ORDER_INFO* orderInfo) -{ - struct mod* mod; - - LLOGLN(0, ("lrail_NotifyIconDelete:")); - mod = ((struct mod_context*)context)->modi; - mod->server_notify_delete(mod, orderInfo->windowId, - orderInfo->notifyIconId); -} - -/*****************************************************************************/ -void DEFAULT_CC -lrail_MonitoredDesktop(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, - MONITORED_DESKTOP_ORDER* monitored_desktop) -{ - int index; - struct mod* mod; - struct rail_monitored_desktop_order rmdo; - - LLOGLN(0, ("lrail_MonitoredDesktop:")); - mod = ((struct mod_context*)context)->modi; - memset(&rmdo, 0, sizeof(rmdo)); - rmdo.active_window_id = monitored_desktop->activeWindowId; - rmdo.num_window_ids = monitored_desktop->numWindowIds; - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER) - { - if (rmdo.num_window_ids > 0) + if ((mod->username[0] != 0) && (mod->password[0] != 0)) { - rmdo.window_ids = (int*)g_malloc(sizeof(int) * rmdo.num_window_ids, 0); - for (index = 0; index < rmdo.num_window_ids; index++) - { - rmdo.window_ids[index] = monitored_desktop->windowIds[index]; - } + /* since we have username and password, we can try nla */ + instance->settings->nla_security = 1; } - } - mod->server_monitored_desktop(mod, &rmdo, orderInfo->fieldFlags); - g_free(rmdo.window_ids); + else + { + instance->settings->nla_security = 0; + } + + return true; } /*****************************************************************************/ void DEFAULT_CC -lrail_NonMonitoredDesktop(rdpContext* context, WINDOW_ORDER_INFO* orderInfo) +lrail_WindowCreate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + WINDOW_STATE_ORDER *window_state) { - struct mod* mod; - struct rail_monitored_desktop_order rmdo; + int index; + struct mod *mod; + struct rail_window_state_order wso; + UNICONV *uniconv; - LLOGLN(0, ("lrail_NonMonitoredDesktop:")); - mod = ((struct mod_context*)context)->modi; - memset(&rmdo, 0, sizeof(rmdo)); - mod->server_monitored_desktop(mod, &rmdo, orderInfo->fieldFlags); + LLOGLN(0, ("llrail_WindowCreate:")); + uniconv = freerdp_uniconv_new(); + mod = ((struct mod_context *)context)->modi; + memset(&wso, 0, sizeof(wso)); + /* copy the window state order */ + wso.owner_window_id = window_state->ownerWindowId; + wso.style = window_state->style; + wso.extended_style = window_state->extendedStyle; + wso.show_state = window_state->showState; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE) + { + wso.title_info = freerdp_uniconv_in(uniconv, + window_state->titleInfo.string, window_state->titleInfo.length); + } + + LLOGLN(0, ("lrail_WindowCreate: %s", wso.title_info)); + wso.client_offset_x = window_state->clientOffsetX; + wso.client_offset_y = window_state->clientOffsetY; + wso.client_area_width = window_state->clientAreaWidth; + wso.client_area_height = window_state->clientAreaHeight; + wso.rp_content = window_state->RPContent; + wso.root_parent_handle = window_state->rootParentHandle; + wso.window_offset_x = window_state->windowOffsetX; + wso.window_offset_y = window_state->windowOffsetY; + wso.window_client_delta_x = window_state->windowClientDeltaX; + wso.window_client_delta_y = window_state->windowClientDeltaY; + wso.window_width = window_state->windowWidth; + wso.window_height = window_state->windowHeight; + wso.num_window_rects = window_state->numWindowRects; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) + { + wso.window_rects = (struct rail_window_rect *) + g_malloc(sizeof(struct rail_window_rect) * wso.num_window_rects, 0); + + for (index = 0; index < wso.num_window_rects; index++) + { + wso.window_rects[index].left = window_state->windowRects[index].left; + wso.window_rects[index].top = window_state->windowRects[index].top; + wso.window_rects[index].right = window_state->windowRects[index].right; + wso.window_rects[index].bottom = window_state->windowRects[index].bottom; + } + } + + wso.visible_offset_x = window_state->visibleOffsetX; + wso.visible_offset_y = window_state->visibleOffsetY; + wso.num_visibility_rects = window_state->numVisibilityRects; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) + { + wso.visibility_rects = (struct rail_window_rect *) + g_malloc(sizeof(struct rail_window_rect) * wso.num_visibility_rects, 0); + + for (index = 0; index < wso.num_visibility_rects; index++) + { + wso.visibility_rects[index].left = window_state->visibilityRects[index].left; + wso.visibility_rects[index].top = window_state->visibilityRects[index].top; + wso.visibility_rects[index].right = window_state->visibilityRects[index].right; + wso.visibility_rects[index].bottom = window_state->visibilityRects[index].bottom; + } + } + + mod->server_window_new_update(mod, orderInfo->windowId, &wso, + orderInfo->fieldFlags); + + xfree(wso.title_info); + g_free(wso.window_rects); + g_free(wso.visibility_rects); + freerdp_uniconv_free(uniconv); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowUpdate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + WINDOW_STATE_ORDER *window_state) +{ + LLOGLN(0, ("lrail_WindowUpdate:")); + lrail_WindowCreate(context, orderInfo, window_state); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowDelete(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) +{ + struct mod *mod; + + LLOGLN(0, ("lrail_WindowDelete:")); + mod = ((struct mod_context *)context)->modi; + mod->server_window_delete(mod, orderInfo->windowId); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowIcon(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + WINDOW_ICON_ORDER *window_icon) +{ + struct mod *mod; + struct rail_icon_info rii; + + LLOGLN(0, ("lrail_WindowIcon:")); + mod = ((struct mod_context *)context)->modi; + memset(&rii, 0, sizeof(rii)); + rii.bpp = window_icon->iconInfo->bpp; + rii.width = window_icon->iconInfo->width; + rii.height = window_icon->iconInfo->height; + rii.cmap_bytes = window_icon->iconInfo->cbColorTable; + rii.mask_bytes = window_icon->iconInfo->cbBitsMask; + rii.data_bytes = window_icon->iconInfo->cbBitsColor; + rii.mask = (char *)(window_icon->iconInfo->bitsMask); + rii.cmap = (char *)(window_icon->iconInfo->colorTable); + rii.data = (char *)(window_icon->iconInfo->bitsColor); + mod->server_window_icon(mod, orderInfo->windowId, + window_icon->iconInfo->cacheEntry, + window_icon->iconInfo->cacheId, &rii, + orderInfo->fieldFlags); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_WindowCachedIcon(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + WINDOW_CACHED_ICON_ORDER *window_cached_icon) +{ + struct mod *mod; + + LLOGLN(0, ("lrail_WindowCachedIcon:")); + mod = ((struct mod_context *)context)->modi; + mod->server_window_cached_icon(mod, orderInfo->windowId, + window_cached_icon->cachedIcon.cacheEntry, + window_cached_icon->cachedIcon.cacheId, + orderInfo->fieldFlags); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_NotifyIconCreate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + NOTIFY_ICON_STATE_ORDER *notify_icon_state) +{ + struct mod *mod; + struct rail_notify_state_order rnso; + UNICONV *uniconv; + + + LLOGLN(0, ("lrail_NotifyIconCreate:")); + uniconv = freerdp_uniconv_new(); + + mod = ((struct mod_context *)context)->modi; + + memset(&rnso, 0, sizeof(rnso)); + rnso.version = notify_icon_state->version; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP) + { + rnso.tool_tip = freerdp_uniconv_in(uniconv, + notify_icon_state->toolTip.string, notify_icon_state->toolTip.length); + } + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) + { + rnso.infotip.timeout = notify_icon_state->infoTip.timeout; + rnso.infotip.flags = notify_icon_state->infoTip.flags; + rnso.infotip.text = freerdp_uniconv_in(uniconv, + notify_icon_state->infoTip.text.string, + notify_icon_state->infoTip.text.length); + rnso.infotip.title = freerdp_uniconv_in(uniconv, + notify_icon_state->infoTip.title.string, + notify_icon_state->infoTip.title.length); + } + + rnso.state = notify_icon_state->state; + rnso.icon_cache_entry = notify_icon_state->icon.cacheEntry; + rnso.icon_cache_id = notify_icon_state->icon.cacheId; + + rnso.icon_info.bpp = notify_icon_state->icon.bpp; + rnso.icon_info.width = notify_icon_state->icon.width; + rnso.icon_info.height = notify_icon_state->icon.height; + rnso.icon_info.cmap_bytes = notify_icon_state->icon.cbColorTable; + rnso.icon_info.mask_bytes = notify_icon_state->icon.cbBitsMask; + rnso.icon_info.data_bytes = notify_icon_state->icon.cbBitsColor; + rnso.icon_info.mask = (char *)(notify_icon_state->icon.bitsMask); + rnso.icon_info.cmap = (char *)(notify_icon_state->icon.colorTable); + rnso.icon_info.data = (char *)(notify_icon_state->icon.bitsColor); + + mod->server_notify_new_update(mod, orderInfo->windowId, + orderInfo->notifyIconId, + &rnso, orderInfo->fieldFlags); + + xfree(rnso.tool_tip); + xfree(rnso.infotip.text); + xfree(rnso.infotip.title); + freerdp_uniconv_free(uniconv); + +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_NotifyIconUpdate(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + NOTIFY_ICON_STATE_ORDER *notify_icon_state) +{ + LLOGLN(0, ("lrail_NotifyIconUpdate:")); + lrail_NotifyIconCreate(context, orderInfo, notify_icon_state); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_NotifyIconDelete(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) +{ + struct mod *mod; + + LLOGLN(0, ("lrail_NotifyIconDelete:")); + mod = ((struct mod_context *)context)->modi; + mod->server_notify_delete(mod, orderInfo->windowId, + orderInfo->notifyIconId); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_MonitoredDesktop(rdpContext *context, WINDOW_ORDER_INFO *orderInfo, + MONITORED_DESKTOP_ORDER *monitored_desktop) +{ + int index; + struct mod *mod; + struct rail_monitored_desktop_order rmdo; + + LLOGLN(0, ("lrail_MonitoredDesktop:")); + mod = ((struct mod_context *)context)->modi; + memset(&rmdo, 0, sizeof(rmdo)); + rmdo.active_window_id = monitored_desktop->activeWindowId; + rmdo.num_window_ids = monitored_desktop->numWindowIds; + + if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER) + { + if (rmdo.num_window_ids > 0) + { + rmdo.window_ids = (int *)g_malloc(sizeof(int) * rmdo.num_window_ids, 0); + + for (index = 0; index < rmdo.num_window_ids; index++) + { + rmdo.window_ids[index] = monitored_desktop->windowIds[index]; + } + } + } + + mod->server_monitored_desktop(mod, &rmdo, orderInfo->fieldFlags); + g_free(rmdo.window_ids); +} + +/*****************************************************************************/ +void DEFAULT_CC +lrail_NonMonitoredDesktop(rdpContext *context, WINDOW_ORDER_INFO *orderInfo) +{ + struct mod *mod; + struct rail_monitored_desktop_order rmdo; + + LLOGLN(0, ("lrail_NonMonitoredDesktop:")); + mod = ((struct mod_context *)context)->modi; + memset(&rmdo, 0, sizeof(rmdo)); + mod->server_monitored_desktop(mod, &rmdo, orderInfo->fieldFlags); } /******************************************************************************/ static boolean DEFAULT_CC -lfreerdp_post_connect(freerdp* instance) +lfreerdp_post_connect(freerdp *instance) { - struct mod* mod; + struct mod *mod; - LLOGLN(0, ("lfreerdp_post_connect:")); - mod = ((struct mod_context*)(instance->context))->modi; - g_memset(mod->password, 0, sizeof(mod->password)); + LLOGLN(0, ("lfreerdp_post_connect:")); + mod = ((struct mod_context *)(instance->context))->modi; + g_memset(mod->password, 0, sizeof(mod->password)); - mod->inst->update->window->WindowCreate = lrail_WindowCreate; - mod->inst->update->window->WindowUpdate = lrail_WindowUpdate; - mod->inst->update->window->WindowDelete = lrail_WindowDelete; - mod->inst->update->window->WindowIcon = lrail_WindowIcon; - mod->inst->update->window->WindowCachedIcon = lrail_WindowCachedIcon; - mod->inst->update->window->NotifyIconCreate = lrail_NotifyIconCreate; - mod->inst->update->window->NotifyIconUpdate = lrail_NotifyIconUpdate; - mod->inst->update->window->NotifyIconDelete = lrail_NotifyIconDelete; - mod->inst->update->window->MonitoredDesktop = lrail_MonitoredDesktop; - mod->inst->update->window->NonMonitoredDesktop = lrail_NonMonitoredDesktop; + mod->inst->update->window->WindowCreate = lrail_WindowCreate; + mod->inst->update->window->WindowUpdate = lrail_WindowUpdate; + mod->inst->update->window->WindowDelete = lrail_WindowDelete; + mod->inst->update->window->WindowIcon = lrail_WindowIcon; + mod->inst->update->window->WindowCachedIcon = lrail_WindowCachedIcon; + mod->inst->update->window->NotifyIconCreate = lrail_NotifyIconCreate; + mod->inst->update->window->NotifyIconUpdate = lrail_NotifyIconUpdate; + mod->inst->update->window->NotifyIconDelete = lrail_NotifyIconDelete; + mod->inst->update->window->MonitoredDesktop = lrail_MonitoredDesktop; + mod->inst->update->window->NonMonitoredDesktop = lrail_NonMonitoredDesktop; - return true; + return true; } /******************************************************************************/ static void DEFAULT_CC -lfreerdp_context_new(freerdp* instance, rdpContext* context) +lfreerdp_context_new(freerdp *instance, rdpContext *context) { - LLOGLN(0, ("lfreerdp_context_new: %p", context)); + LLOGLN(0, ("lfreerdp_context_new: %p", context)); } /******************************************************************************/ static void DEFAULT_CC -lfreerdp_context_free(freerdp* instance, rdpContext* context) +lfreerdp_context_free(freerdp *instance, rdpContext *context) { - LLOGLN(0, ("lfreerdp_context_free:")); + LLOGLN(0, ("lfreerdp_context_free:")); } /******************************************************************************/ static int DEFAULT_CC -lfreerdp_receive_channel_data(freerdp* instance, int channelId, uint8* data, +lfreerdp_receive_channel_data(freerdp *instance, int channelId, uint8 *data, int size, int flags, int total_size) { - struct mod* mod; - int lchid; - int index; - int error; + struct mod *mod; + int lchid; + int index; + int error; - mod = ((struct mod_context*)(instance->context))->modi; - lchid = -1; - for (index = 0; index < instance->settings->num_channels; index++) - { - if (instance->settings->channels[index].channel_id == channelId) + mod = ((struct mod_context *)(instance->context))->modi; + lchid = -1; + + for (index = 0; index < instance->settings->num_channels; index++) { - lchid = index; - break; + if (instance->settings->channels[index].channel_id == channelId) + { + lchid = index; + break; + } } - } - if (lchid >= 0) - { - LLOGLN(10, ("lfreerdp_receive_channel_data: server to client")); - error = mod->server_send_to_channel(mod, lchid, (char*)data, size, - total_size, flags); - if (error != 0) + + if (lchid >= 0) { - LLOGLN(0, ("lfreerdp_receive_channel_data: error %d", error)); + LLOGLN(10, ("lfreerdp_receive_channel_data: server to client")); + error = mod->server_send_to_channel(mod, lchid, (char *)data, size, + total_size, flags); + + if (error != 0) + { + LLOGLN(0, ("lfreerdp_receive_channel_data: error %d", error)); + } } - } - else - { - LLOGLN(0, ("lfreerdp_receive_channel_data: bad lchid")); - } - return 0; + else + { + LLOGLN(0, ("lfreerdp_receive_channel_data: bad lchid")); + } + + return 0; } /******************************************************************************/ static boolean DEFAULT_CC -lfreerdp_authenticate(freerdp* instance, char** username, - char** password, char** domain) +lfreerdp_authenticate(freerdp *instance, char **username, + char **password, char **domain) { - LLOGLN(0, ("lfreerdp_authenticate:")); - return true; + LLOGLN(0, ("lfreerdp_authenticate:")); + return true; } /******************************************************************************/ static boolean DEFAULT_CC -lfreerdp_verify_certificate(freerdp* instance, char* subject, char* issuer, - char* fingerprint) +lfreerdp_verify_certificate(freerdp *instance, char *subject, char *issuer, + char *fingerprint) { - LLOGLN(0, ("lfreerdp_verify_certificate:")); - return true; + LLOGLN(0, ("lfreerdp_verify_certificate:")); + return true; } /******************************************************************************/ -struct mod* EXPORT_CC +struct mod *EXPORT_CC mod_init(void) { - struct mod* mod; - modContext* lcon; + struct mod *mod; + modContext *lcon; - LLOGLN(0, ("mod_init:")); - mod = (struct mod*)g_malloc(sizeof(struct mod), 1); - freerdp_get_version(&(mod->vmaj), &(mod->vmin), &(mod->vrev)); - LLOGLN(0, (" FreeRDP version major %d minor %d revision %d", - mod->vmaj, mod->vmin, mod->vrev)); - mod->size = sizeof(struct mod); - mod->version = CURRENT_MOD_VER; - mod->handle = (tbus)mod; - mod->mod_connect = lxrdp_connect; - mod->mod_start = lxrdp_start; - mod->mod_event = lxrdp_event; - mod->mod_signal = lxrdp_signal; - mod->mod_end = lxrdp_end; - mod->mod_set_param = lxrdp_set_param; - mod->mod_session_change = lxrdp_session_change; - mod->mod_get_wait_objs = lxrdp_get_wait_objs; - mod->mod_check_wait_objs = lxrdp_check_wait_objs; + LLOGLN(0, ("mod_init:")); + mod = (struct mod *)g_malloc(sizeof(struct mod), 1); + freerdp_get_version(&(mod->vmaj), &(mod->vmin), &(mod->vrev)); + LLOGLN(0, (" FreeRDP version major %d minor %d revision %d", + mod->vmaj, mod->vmin, mod->vrev)); + mod->size = sizeof(struct mod); + mod->version = CURRENT_MOD_VER; + mod->handle = (tbus)mod; + mod->mod_connect = lxrdp_connect; + mod->mod_start = lxrdp_start; + mod->mod_event = lxrdp_event; + mod->mod_signal = lxrdp_signal; + mod->mod_end = lxrdp_end; + mod->mod_set_param = lxrdp_set_param; + mod->mod_session_change = lxrdp_session_change; + mod->mod_get_wait_objs = lxrdp_get_wait_objs; + mod->mod_check_wait_objs = lxrdp_check_wait_objs; - mod->inst = freerdp_new(); - mod->inst->PreConnect = lfreerdp_pre_connect; - mod->inst->PostConnect = lfreerdp_post_connect; - mod->inst->context_size = sizeof(modContext); - mod->inst->ContextNew = lfreerdp_context_new; - mod->inst->ContextFree = lfreerdp_context_free; - mod->inst->ReceiveChannelData = lfreerdp_receive_channel_data; - mod->inst->Authenticate = lfreerdp_authenticate; - mod->inst->VerifyCertificate = lfreerdp_verify_certificate; + mod->inst = freerdp_new(); + mod->inst->PreConnect = lfreerdp_pre_connect; + mod->inst->PostConnect = lfreerdp_post_connect; + mod->inst->context_size = sizeof(modContext); + mod->inst->ContextNew = lfreerdp_context_new; + mod->inst->ContextFree = lfreerdp_context_free; + mod->inst->ReceiveChannelData = lfreerdp_receive_channel_data; + mod->inst->Authenticate = lfreerdp_authenticate; + mod->inst->VerifyCertificate = lfreerdp_verify_certificate; - freerdp_context_new(mod->inst); + freerdp_context_new(mod->inst); - lcon = (modContext*)(mod->inst->context); - lcon->modi = mod; - LLOGLN(10, ("mod_init: mod %p", mod)); + lcon = (modContext *)(mod->inst->context); + lcon->modi = mod; + LLOGLN(10, ("mod_init: mod %p", mod)); - return mod; + return mod; } /******************************************************************************/ int EXPORT_CC -mod_exit(struct mod* mod) +mod_exit(struct mod *mod) { - LLOGLN(0, ("mod_exit:")); - if (mod == 0) - { - return 0; - } - if (mod->inst == NULL) - { - LLOGLN(0, ("mod_exit - null pointer for inst:")); + LLOGLN(0, ("mod_exit:")); + + if (mod == 0) + { + return 0; + } + + if (mod->inst == NULL) + { + LLOGLN(0, ("mod_exit - null pointer for inst:")); + g_free(mod); + return 0 ; + } + + freerdp_disconnect(mod->inst); + + if ((mod->vmaj == 1) && (mod->vmin == 0) && (mod->vrev == 1)) + { + /* this version has a bug with double free in freerdp_free */ + } + else + { + freerdp_context_free(mod->inst); + } + + freerdp_free(mod->inst); g_free(mod); - return 0 ; - } - freerdp_disconnect(mod->inst); - if ((mod->vmaj == 1) && (mod->vmin == 0) && (mod->vrev == 1)) - { - /* this version has a bug with double free in freerdp_free */ - } - else - { - freerdp_context_free(mod->inst); - } - freerdp_free(mod->inst); - g_free(mod); - return 0; + return 0; } diff --git a/genkeymap/genkeymap.c b/genkeymap/genkeymap.c index 0d0a9a44..46513513 100644 --- a/genkeymap/genkeymap.c +++ b/genkeymap/genkeymap.c @@ -41,75 +41,87 @@ int main(int argc, char **argv) { - const char* programname; - char text[256]; - char* displayname = NULL; - char* outfname; - char* sections[5] = {"noshift", "shift", "altgr", "capslock", "shiftcapslock"}; - int states[5] = {0, 1, 0x80, 2, 3}; - int i; - int idx; - int char_count; - int nbytes = 0; - int unicode; - Display* dpy; - KeySym ks; - FILE* outf; - XKeyPressedEvent e; - wchar_t wtext[256]; + const char *programname; + char text[256]; + char *displayname = NULL; + char *outfname; + char *sections[5] = {"noshift", "shift", "altgr", "capslock", "shiftcapslock"}; + int states[5] = {0, 1, 0x80, 2, 3}; + int i; + int idx; + int char_count; + int nbytes = 0; + int unicode; + Display *dpy; + KeySym ks; + FILE *outf; + XKeyPressedEvent e; + wchar_t wtext[256]; + + setlocale(LC_CTYPE, ""); + programname = argv[0]; + + if (argc != 2) + { + fprintf(stderr, "Usage: %s out_filename\n", programname); + fprintf(stderr, "Example: %s /etc/xrdp/km-0409.ini\n", programname); + return 1; + } + + outfname = argv[1]; + dpy = XOpenDisplay(displayname); + + if (!dpy) + { + fprintf(stderr, "%s: unable to open display '%s'\n", + programname, XDisplayName(displayname)); + return 1; + } + + outf = fopen(outfname, "w"); + + if (outf == NULL) + { + fprintf(stderr, "%s: unable to create file '%s'\n", programname, outfname); + XCloseDisplay(dpy); + return 1; + } + + memset(&e, 0, sizeof(e)); + e.type = KeyPress; + e.serial = 16; + e.send_event = True; + e.display = dpy; + e.same_screen = True; + + for (idx = 0; idx < 5; idx++) /* Sections and states */ + { + fprintf(outf, "[%s]\n", sections[idx]); + e.state = states[idx]; + + for (i = 8; i <= 137; i++) /* Keycodes */ + { + e.keycode = i; + nbytes = XLookupString(&e, text, 255, &ks, NULL); + text[nbytes] = 0; + char_count = mbstowcs(wtext, text, 255); + unicode = 0; + + if (char_count == 1) + { + unicode = wtext[0]; + } + + fprintf(outf, "Key%d=%d:%d\n", i, (int) ks, unicode); + } + + if (idx != 4) + { + fprintf(outf, "\n"); + } + } - setlocale(LC_CTYPE, ""); - programname = argv[0]; - if (argc != 2) - { - fprintf(stderr, "Usage: %s out_filename\n", programname); - fprintf(stderr, "Example: %s /etc/xrdp/km-0409.ini\n", programname); - return 1; - } - outfname = argv[1]; - dpy = XOpenDisplay(displayname); - if (!dpy) - { - fprintf(stderr, "%s: unable to open display '%s'\n", - programname, XDisplayName(displayname)); - return 1; - } - outf = fopen(outfname, "w"); - if (outf == NULL) - { - fprintf(stderr, "%s: unable to create file '%s'\n", programname, outfname); XCloseDisplay(dpy); - return 1; - } - memset(&e, 0, sizeof(e)); - e.type = KeyPress; - e.serial = 16; - e.send_event = True; - e.display = dpy; - e.same_screen = True; - for (idx = 0; idx < 5; idx++) /* Sections and states */ - { - fprintf(outf, "[%s]\n", sections[idx]); - e.state = states[idx]; - for (i = 8; i <= 137; i++) /* Keycodes */ - { - e.keycode = i; - nbytes = XLookupString(&e, text, 255, &ks, NULL); - text[nbytes] = 0; - char_count = mbstowcs(wtext, text, 255); - unicode = 0; - if (char_count == 1) - { - unicode = wtext[0]; - } - fprintf(outf, "Key%d=%d:%d\n", i, (int) ks, unicode); - } - if (idx != 4) - { - fprintf(outf, "\n"); - } - } - XCloseDisplay(dpy); - fclose(outf); - return 0; + fclose(outf); + return 0; } diff --git a/keygen/keygen.c b/keygen/keygen.c index e984572b..d1495011 100644 --- a/keygen/keygen.c +++ b/keygen/keygen.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2007-2010 - - rsa key generator for xrdp - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * rsa key generator for xrdp + */ /* references: @@ -37,74 +35,74 @@ static tui8 g_exponent[4] = { - 0x01, 0x00, 0x01, 0x00 + 0x01, 0x00, 0x01, 0x00 }; static tui8 g_ppk_e[4] = { - 0x5B, 0x7B, 0x88, 0xC0 + 0x5B, 0x7B, 0x88, 0xC0 }; static tui8 g_ppk_n[72] = { - 0x3D, 0x3A, 0x5E, 0xBD, 0x72, 0x43, 0x3E, 0xC9, - 0x4D, 0xBB, 0xC1, 0x1E, 0x4A, 0xBA, 0x5F, 0xCB, - 0x3E, 0x88, 0x20, 0x87, 0xEF, 0xF5, 0xC1, 0xE2, - 0xD7, 0xB7, 0x6B, 0x9A, 0xF2, 0x52, 0x45, 0x95, - 0xCE, 0x63, 0x65, 0x6B, 0x58, 0x3A, 0xFE, 0xEF, - 0x7C, 0xE7, 0xBF, 0xFE, 0x3D, 0xF6, 0x5C, 0x7D, - 0x6C, 0x5E, 0x06, 0x09, 0x1A, 0xF5, 0x61, 0xBB, - 0x20, 0x93, 0x09, 0x5F, 0x05, 0x6D, 0xEA, 0x87, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x3D, 0x3A, 0x5E, 0xBD, 0x72, 0x43, 0x3E, 0xC9, + 0x4D, 0xBB, 0xC1, 0x1E, 0x4A, 0xBA, 0x5F, 0xCB, + 0x3E, 0x88, 0x20, 0x87, 0xEF, 0xF5, 0xC1, 0xE2, + 0xD7, 0xB7, 0x6B, 0x9A, 0xF2, 0x52, 0x45, 0x95, + 0xCE, 0x63, 0x65, 0x6B, 0x58, 0x3A, 0xFE, 0xEF, + 0x7C, 0xE7, 0xBF, 0xFE, 0x3D, 0xF6, 0x5C, 0x7D, + 0x6C, 0x5E, 0x06, 0x09, 0x1A, 0xF5, 0x61, 0xBB, + 0x20, 0x93, 0x09, 0x5F, 0x05, 0x6D, 0xEA, 0x87, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static tui8 g_ppk_d[108] = { - 0x87, 0xA7, 0x19, 0x32, 0xDA, 0x11, 0x87, 0x55, - 0x58, 0x00, 0x16, 0x16, 0x25, 0x65, 0x68, 0xF8, - 0x24, 0x3E, 0xE6, 0xFA, 0xE9, 0x67, 0x49, 0x94, - 0xCF, 0x92, 0xCC, 0x33, 0x99, 0xE8, 0x08, 0x60, - 0x17, 0x9A, 0x12, 0x9F, 0x24, 0xDD, 0xB1, 0x24, - 0x99, 0xC7, 0x3A, 0xB8, 0x0A, 0x7B, 0x0D, 0xDD, - 0x35, 0x07, 0x79, 0x17, 0x0B, 0x51, 0x9B, 0xB3, - 0xC7, 0x10, 0x01, 0x13, 0xE7, 0x3F, 0xF3, 0x5F, - 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 + 0x87, 0xA7, 0x19, 0x32, 0xDA, 0x11, 0x87, 0x55, + 0x58, 0x00, 0x16, 0x16, 0x25, 0x65, 0x68, 0xF8, + 0x24, 0x3E, 0xE6, 0xFA, 0xE9, 0x67, 0x49, 0x94, + 0xCF, 0x92, 0xCC, 0x33, 0x99, 0xE8, 0x08, 0x60, + 0x17, 0x9A, 0x12, 0x9F, 0x24, 0xDD, 0xB1, 0x24, + 0x99, 0xC7, 0x3A, 0xB8, 0x0A, 0x7B, 0x0D, 0xDD, + 0x35, 0x07, 0x79, 0x17, 0x0B, 0x51, 0x9B, 0xB3, + 0xC7, 0x10, 0x01, 0x13, 0xE7, 0x3F, 0xF3, 0x5F, + 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 tui8 g_testkey[176] = { - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5c, 0x00, - 0x52, 0x53, 0x41, 0x31, 0x48, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x79, 0x6f, 0xb4, 0xdf, - 0xa6, 0x95, 0xb9, 0xa9, 0x61, 0xe3, 0xc4, 0x5e, - 0xff, 0x6b, 0xd8, 0x81, 0x8a, 0x12, 0x4a, 0x93, - 0x42, 0x97, 0x18, 0x93, 0xac, 0xd1, 0x3a, 0x38, - 0x3c, 0x68, 0x50, 0x19, 0x31, 0xb6, 0x84, 0x51, - 0x79, 0xfb, 0x1c, 0xe7, 0xe3, 0x99, 0x20, 0xc7, - 0x84, 0xdf, 0xd1, 0xaa, 0xb5, 0x15, 0xef, 0x47, - 0x7e, 0xfc, 0x88, 0xeb, 0x29, 0xc3, 0x27, 0x5a, - 0x35, 0xf8, 0xfd, 0xaa, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x48, 0x00, - 0x32, 0x3b, 0xde, 0x6f, 0x18, 0x97, 0x1e, 0xc3, - 0x6b, 0x2b, 0x2d, 0xe4, 0xfc, 0x2d, 0xa2, 0x8e, - 0x32, 0x3c, 0xf3, 0x1b, 0x24, 0x90, 0x57, 0x4d, - 0x8e, 0xe4, 0x69, 0xfc, 0x16, 0x8d, 0x41, 0x92, - 0x78, 0xc7, 0x9c, 0xb4, 0x26, 0xff, 0xe8, 0x3e, - 0xa1, 0x8a, 0xf5, 0x57, 0xc0, 0x7f, 0x3e, 0x21, - 0x17, 0x32, 0x30, 0x6f, 0x79, 0xe1, 0x36, 0xcd, - 0xb6, 0x8e, 0xbe, 0x57, 0x57, 0xd2, 0xa9, 0x36 + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5c, 0x00, + 0x52, 0x53, 0x41, 0x31, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x79, 0x6f, 0xb4, 0xdf, + 0xa6, 0x95, 0xb9, 0xa9, 0x61, 0xe3, 0xc4, 0x5e, + 0xff, 0x6b, 0xd8, 0x81, 0x8a, 0x12, 0x4a, 0x93, + 0x42, 0x97, 0x18, 0x93, 0xac, 0xd1, 0x3a, 0x38, + 0x3c, 0x68, 0x50, 0x19, 0x31, 0xb6, 0x84, 0x51, + 0x79, 0xfb, 0x1c, 0xe7, 0xe3, 0x99, 0x20, 0xc7, + 0x84, 0xdf, 0xd1, 0xaa, 0xb5, 0x15, 0xef, 0x47, + 0x7e, 0xfc, 0x88, 0xeb, 0x29, 0xc3, 0x27, 0x5a, + 0x35, 0xf8, 0xfd, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x48, 0x00, + 0x32, 0x3b, 0xde, 0x6f, 0x18, 0x97, 0x1e, 0xc3, + 0x6b, 0x2b, 0x2d, 0xe4, 0xfc, 0x2d, 0xa2, 0x8e, + 0x32, 0x3c, 0xf3, 0x1b, 0x24, 0x90, 0x57, 0x4d, + 0x8e, 0xe4, 0x69, 0xfc, 0x16, 0x8d, 0x41, 0x92, + 0x78, 0xc7, 0x9c, 0xb4, 0x26, 0xff, 0xe8, 0x3e, + 0xa1, 0x8a, 0xf5, 0x57, 0xc0, 0x7f, 0x3e, 0x21, + 0x17, 0x32, 0x30, 0x6f, 0x79, 0xe1, 0x36, 0xcd, + 0xb6, 0x8e, 0xbe, 0x57, 0x57, 0xd2, 0xa9, 0x36 }; /* this is the installed signature */ -char inst_pub_sig[]="0x6a,0x41,0xb1,0x43,0xcf,0x47,0x6f,0xf1,0xe6,0xcc,0xa1,\ +char inst_pub_sig[] = "0x6a,0x41,0xb1,0x43,0xcf,0x47,0x6f,0xf1,0xe6,0xcc,0xa1,\ 0x72,0x97,0xd9,0xe1,0x85,0x15,0xb3,0xc2,0x39,0xa0,0xa6,0x26,0x1a,0xb6,\ 0x49,0x01,0xfa,0xa6,0xda,0x60,0xd7,0x45,0xf7,0x2c,0xee,0xe4,0x8e,0x64,\ 0x2e,0x37,0x49,0xf0,0x4c,0x94,0x6f,0x08,0xf5,0x63,0x4c,0x56,0x29,0x55,\ @@ -115,212 +113,230 @@ char inst_pub_sig[]="0x6a,0x41,0xb1,0x43,0xcf,0x47,0x6f,0xf1,0xe6,0xcc,0xa1,\ static int APP_CC out_params(void) { - g_writeln(""); - g_writeln("xrdp rsa key gen utility examples"); - g_writeln(" xrdp-keygen xrdp ['path and file name' | auto]"); - g_writeln(" xrdp-keygen test"); - g_writeln(""); - return 0; + g_writeln(""); + g_writeln("xrdp rsa key gen utility examples"); + g_writeln(" xrdp-keygen xrdp ['path and file name' | auto]"); + g_writeln(" xrdp-keygen test"); + g_writeln(""); + return 0; } /*****************************************************************************/ /* this is the special key signing algorithm */ static int APP_CC -sign_key(char* e_data, int e_len, char* n_data, int n_len, - char* sign_data, int sign_len) +sign_key(char *e_data, int e_len, char *n_data, int n_len, + char *sign_data, int sign_len) { - char* key; - char* md5_final; - void* md5; + char *key; + char *md5_final; + void *md5; - if ((e_len != 4) || (n_len != 64) || (sign_len != 64)) - { - return 1; - } - key = (char*)g_malloc(176, 0); - md5_final = (char*)g_malloc(64, 0); - md5 = ssl_md5_info_create(); - /* copy the test key */ - g_memcpy(key, g_testkey, 176); - /* replace e and n */ - g_memcpy(key + 32, e_data, 4); - g_memcpy(key + 36, n_data, 64); - ssl_md5_clear(md5); - /* the first 108 bytes */ - ssl_md5_transform(md5, key, 108); - /* set the whole thing with 0xff */ - g_memset(md5_final, 0xff, 64); - /* digest 16 bytes */ - ssl_md5_complete(md5, md5_final); - /* set non 0xff array items */ - md5_final[16] = 0; - md5_final[62] = 1; - md5_final[63] = 0; - /* encrypt */ - ssl_mod_exp(sign_data, 64, md5_final, 64, (char*)g_ppk_n, 64, - (char*)g_ppk_d, 64); - /* cleanup */ - ssl_md5_info_delete(md5); - g_free(key); - g_free(md5_final); - return 0; + if ((e_len != 4) || (n_len != 64) || (sign_len != 64)) + { + return 1; + } + + key = (char *)g_malloc(176, 0); + md5_final = (char *)g_malloc(64, 0); + md5 = ssl_md5_info_create(); + /* copy the test key */ + g_memcpy(key, g_testkey, 176); + /* replace e and n */ + g_memcpy(key + 32, e_data, 4); + g_memcpy(key + 36, n_data, 64); + ssl_md5_clear(md5); + /* the first 108 bytes */ + ssl_md5_transform(md5, key, 108); + /* set the whole thing with 0xff */ + g_memset(md5_final, 0xff, 64); + /* digest 16 bytes */ + ssl_md5_complete(md5, md5_final); + /* set non 0xff array items */ + md5_final[16] = 0; + md5_final[62] = 1; + md5_final[63] = 0; + /* encrypt */ + ssl_mod_exp(sign_data, 64, md5_final, 64, (char *)g_ppk_n, 64, + (char *)g_ppk_d, 64); + /* cleanup */ + ssl_md5_info_delete(md5); + g_free(key); + g_free(md5_final); + return 0; } /*****************************************************************************/ static int APP_CC -write_out_line(int fd, char* name, char* data, int len) +write_out_line(int fd, char *name, char *data, int len) { - int max; - int error; - int index; - int data_item; - int buf_pos; - char* buf; - char* text; + int max; + int error; + int index; + int data_item; + int buf_pos; + char *buf; + char *text; - text = (char*)g_malloc(256, 0); - max = len; - max = max * 10; - buf_pos = g_strlen(name); - max = max + buf_pos + 16; - buf = (char*)g_malloc(max, 0); - g_strncpy(buf, name, max - 1); - buf[buf_pos] = '='; - buf_pos++; - for (index = 0; index < len; index++) - { - data_item = (tui8)(data[index]); - g_snprintf(text, 255, "0x%2.2x", data_item); - if (index != 0) + text = (char *)g_malloc(256, 0); + max = len; + max = max * 10; + buf_pos = g_strlen(name); + max = max + buf_pos + 16; + buf = (char *)g_malloc(max, 0); + g_strncpy(buf, name, max - 1); + buf[buf_pos] = '='; + buf_pos++; + + for (index = 0; index < len; index++) { - buf[buf_pos] = ','; - buf_pos++; + data_item = (tui8)(data[index]); + g_snprintf(text, 255, "0x%2.2x", data_item); + + if (index != 0) + { + buf[buf_pos] = ','; + buf_pos++; + } + + buf[buf_pos] = text[0]; + buf_pos++; + buf[buf_pos] = text[1]; + buf_pos++; + buf[buf_pos] = text[2]; + buf_pos++; + buf[buf_pos] = text[3]; + buf_pos++; } - buf[buf_pos] = text[0]; + + buf[buf_pos] = '\n'; buf_pos++; - buf[buf_pos] = text[1]; - buf_pos++; - buf[buf_pos] = text[2]; - buf_pos++; - buf[buf_pos] = text[3]; - buf_pos++; - } - buf[buf_pos] = '\n'; - buf_pos++; - buf[buf_pos] = 0; - error = g_file_write(fd, buf, buf_pos) == -1; - g_free(buf); - g_free(text); - return error; + buf[buf_pos] = 0; + error = g_file_write(fd, buf, buf_pos) == -1; + g_free(buf); + g_free(text); + return error; } /*****************************************************************************/ static int APP_CC -save_all(char* e_data, int e_len, char* n_data, int n_len, - char* d_data, int d_len, char* sign_data, int sign_len, - const char* path_and_file_name) +save_all(char *e_data, int e_len, char *n_data, int n_len, + char *d_data, int d_len, char *sign_data, int sign_len, + const char *path_and_file_name) { - int fd; - char filename[256]; + int fd; + char filename[256]; - if (path_and_file_name == 0) - { - g_strncpy(filename, "rsakeys.ini", 255); - } - else - { - g_strncpy(filename, path_and_file_name, 255); - } - g_writeln("saving to %s", filename); - g_writeln(""); - if (g_file_exist(filename)) - { - if (g_file_delete(filename) == 0) + if (path_and_file_name == 0) { - g_writeln("problem deleting %s, maybe no rights", filename); - return 1; + g_strncpy(filename, "rsakeys.ini", 255); } - } - fd = g_file_open(filename); - if (fd > 0) - { - if (g_file_write(fd, "[keys]\n", 7) == -1) + else { - g_writeln("problem writing to %s, maybe no rights", filename); - return 1; + g_strncpy(filename, path_and_file_name, 255); } - write_out_line(fd, "pub_exp", e_data, e_len); - write_out_line(fd, "pub_mod", n_data, n_len); - write_out_line(fd, "pub_sig", sign_data, sign_len); - write_out_line(fd, "pri_exp", d_data, d_len); - } - else - { - g_writeln("problem opening %s, maybe no rights", filename); - return 1; - } - g_file_close(fd); - return 0; -} -/*****************************************************************************/ -static int APP_CC -key_gen(const char* path_and_file_name) -{ - char* e_data; - char* n_data; - char* d_data; - char* sign_data; - int e_len; - int n_len; - int d_len; - int sign_len; - int error; - - e_data = (char*)g_exponent; - n_data = (char*)g_malloc(64, 0); - d_data = (char*)g_malloc(64, 0); - sign_data = (char*)g_malloc(64, 0); - e_len = 4; - n_len = 64; - d_len = 64; - sign_len = 64; - error = 0; - g_writeln(""); - g_writeln("Generating %d bit rsa key...", MY_KEY_SIZE); - g_writeln(""); - if (error == 0) - { - error = ssl_gen_key_xrdp1(MY_KEY_SIZE, e_data, e_len, n_data, n_len, - d_data, d_len); - if (error != 0) - { - g_writeln("error %d in key_gen, ssl_gen_key_xrdp1", error); - } - } - if (error == 0) - { - g_writeln("ssl_gen_key_xrdp1 ok"); + g_writeln("saving to %s", filename); g_writeln(""); - error = sign_key(e_data, e_len, n_data, n_len, sign_data, sign_len); - if (error != 0) + + if (g_file_exist(filename)) { - g_writeln("error %d in key_gen, sign_key", error); + if (g_file_delete(filename) == 0) + { + g_writeln("problem deleting %s, maybe no rights", filename); + return 1; + } } - } - if (error == 0) - { - error = save_all(e_data, e_len, n_data, n_len, d_data, d_len, - sign_data, sign_len, path_and_file_name); - if (error != 0) + + fd = g_file_open(filename); + + if (fd > 0) { - g_writeln("error %d in key_gen, save_all", error); + if (g_file_write(fd, "[keys]\n", 7) == -1) + { + g_writeln("problem writing to %s, maybe no rights", filename); + return 1; + } + + write_out_line(fd, "pub_exp", e_data, e_len); + write_out_line(fd, "pub_mod", n_data, n_len); + write_out_line(fd, "pub_sig", sign_data, sign_len); + write_out_line(fd, "pri_exp", d_data, d_len); } - } - g_free(n_data); - g_free(d_data); - g_free(sign_data); - return error; + else + { + g_writeln("problem opening %s, maybe no rights", filename); + return 1; + } + + g_file_close(fd); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +key_gen(const char *path_and_file_name) +{ + char *e_data; + char *n_data; + char *d_data; + char *sign_data; + int e_len; + int n_len; + int d_len; + int sign_len; + int error; + + e_data = (char *)g_exponent; + n_data = (char *)g_malloc(64, 0); + d_data = (char *)g_malloc(64, 0); + sign_data = (char *)g_malloc(64, 0); + e_len = 4; + n_len = 64; + d_len = 64; + sign_len = 64; + error = 0; + g_writeln(""); + g_writeln("Generating %d bit rsa key...", MY_KEY_SIZE); + g_writeln(""); + + if (error == 0) + { + error = ssl_gen_key_xrdp1(MY_KEY_SIZE, e_data, e_len, n_data, n_len, + d_data, d_len); + + if (error != 0) + { + g_writeln("error %d in key_gen, ssl_gen_key_xrdp1", error); + } + } + + if (error == 0) + { + g_writeln("ssl_gen_key_xrdp1 ok"); + g_writeln(""); + error = sign_key(e_data, e_len, n_data, n_len, sign_data, sign_len); + + if (error != 0) + { + g_writeln("error %d in key_gen, sign_key", error); + } + } + + if (error == 0) + { + error = save_all(e_data, e_len, n_data, n_len, d_data, d_len, + sign_data, sign_len, path_and_file_name); + + if (error != 0) + { + g_writeln("error %d in key_gen, save_all", error); + } + } + + g_free(n_data); + g_free(d_data); + g_free(sign_data); + return error; } /*****************************************************************************/ @@ -328,146 +344,156 @@ key_gen(const char* path_and_file_name) static int APP_CC key_gen_run_it(void) { - int fd; - int index; - int rv; - struct list* names; - struct list* values; - char* name; - char* value; + int fd; + int index; + int rv; + struct list *names; + struct list *values; + char *name; + char *value; - if (!g_file_exist("/etc/xrdp/rsakeys.ini")) - { - return 1; - } - if (g_file_get_size("/etc/xrdp/rsakeys.ini") < 10) - { - return 1; - } - fd = g_file_open("/etc/xrdp/rsakeys.ini"); - if (fd < 0) - { - return 1; - } - rv = 0; - names = list_create(); - names->auto_free = 1; - values = list_create(); - values->auto_free = 1; - if (file_read_section(fd, "keys", names, values) == 0) - { - for (index = 0; index < names->count; index++) + if (!g_file_exist("/etc/xrdp/rsakeys.ini")) { - name = (char*)list_get_item(names, index); - value = (char*)list_get_item(values, index); - if (g_strcasecmp(name, "pub_sig") == 0) - { - if (g_strcasecmp(value, inst_pub_sig) == 0) - { - rv = 1; - } - } + return 1; } - } - else - { - g_writeln("error reading keys section of rsakeys.ini"); - } - list_delete(names); - list_delete(values); - g_file_close(fd); - return rv; + + if (g_file_get_size("/etc/xrdp/rsakeys.ini") < 10) + { + return 1; + } + + fd = g_file_open("/etc/xrdp/rsakeys.ini"); + + if (fd < 0) + { + return 1; + } + + rv = 0; + names = list_create(); + names->auto_free = 1; + values = list_create(); + values->auto_free = 1; + + if (file_read_section(fd, "keys", names, values) == 0) + { + for (index = 0; index < names->count; index++) + { + name = (char *)list_get_item(names, index); + value = (char *)list_get_item(values, index); + + if (g_strcasecmp(name, "pub_sig") == 0) + { + if (g_strcasecmp(value, inst_pub_sig) == 0) + { + rv = 1; + } + } + } + } + else + { + g_writeln("error reading keys section of rsakeys.ini"); + } + + list_delete(names); + list_delete(values); + g_file_close(fd); + return rv; } /*****************************************************************************/ static int APP_CC key_gen_auto(void) { - if (key_gen_run_it()) - { - return key_gen("/etc/xrdp/rsakeys.ini"); - } - g_writeln("xrdp-keygen does not need to run"); - return 0; + if (key_gen_run_it()) + { + return key_gen("/etc/xrdp/rsakeys.ini"); + } + + g_writeln("xrdp-keygen does not need to run"); + return 0; } /*****************************************************************************/ static int APP_CC key_test(void) { - char* md5_final; - char* sig; - void* md5; + char *md5_final; + char *sig; + void *md5; - md5_final = (char*)g_malloc(64, 0); - sig = (char*)g_malloc(64, 0); - md5 = ssl_md5_info_create(); - g_writeln("original key is:"); - g_hexdump((char*)g_testkey, 176); - g_writeln("original exponent is:"); - g_hexdump((char*)g_testkey + 32, 4); - g_writeln("original modulus is:"); - g_hexdump((char*)g_testkey + 36, 64); - g_writeln("original signature is:"); - g_hexdump((char*)g_testkey + 112, 64); - ssl_md5_clear(md5); - ssl_md5_transform(md5, (char*)g_testkey, 108); - g_memset(md5_final, 0xff, 64); - ssl_md5_complete(md5, md5_final); - g_writeln("md5 hash of first 108 bytes of this key is:"); - g_hexdump(md5_final, 16); - md5_final[16] = 0; - md5_final[62] = 1; - md5_final[63] = 0; - ssl_mod_exp(sig, 64, md5_final, 64, (char*)g_ppk_n, 64, (char*)g_ppk_d, 64); - g_writeln("produced signature(this should match original \ + md5_final = (char *)g_malloc(64, 0); + sig = (char *)g_malloc(64, 0); + md5 = ssl_md5_info_create(); + g_writeln("original key is:"); + g_hexdump((char *)g_testkey, 176); + g_writeln("original exponent is:"); + g_hexdump((char *)g_testkey + 32, 4); + g_writeln("original modulus is:"); + g_hexdump((char *)g_testkey + 36, 64); + g_writeln("original signature is:"); + g_hexdump((char *)g_testkey + 112, 64); + ssl_md5_clear(md5); + ssl_md5_transform(md5, (char *)g_testkey, 108); + g_memset(md5_final, 0xff, 64); + ssl_md5_complete(md5, md5_final); + g_writeln("md5 hash of first 108 bytes of this key is:"); + g_hexdump(md5_final, 16); + md5_final[16] = 0; + md5_final[62] = 1; + md5_final[63] = 0; + ssl_mod_exp(sig, 64, md5_final, 64, (char *)g_ppk_n, 64, (char *)g_ppk_d, 64); + g_writeln("produced signature(this should match original \ signature above) is:"); - g_hexdump(sig, 64); - g_memset(md5_final, 0, 64); - ssl_mod_exp(md5_final, 64, (char*)g_testkey + 112, 64, (char*)g_ppk_n, 64, - (char*)g_ppk_e, 4); - g_writeln("decrypted hash of first 108 bytes of this key is:"); - g_hexdump(md5_final, 64); - ssl_md5_info_delete(md5); - g_free(md5_final); - g_free(sig); - return 0; + g_hexdump(sig, 64); + g_memset(md5_final, 0, 64); + ssl_mod_exp(md5_final, 64, (char *)g_testkey + 112, 64, (char *)g_ppk_n, 64, + (char *)g_ppk_e, 4); + g_writeln("decrypted hash of first 108 bytes of this key is:"); + g_hexdump(md5_final, 64); + ssl_md5_info_delete(md5); + g_free(md5_final); + g_free(sig); + return 0; } /*****************************************************************************/ int DEFAULT_CC -main(int argc, char** argv) +main(int argc, char **argv) { - if (argc > 1) - { - if (g_strcasecmp(argv[1], "xrdp") == 0) + if (argc > 1) { - if (argc > 2) - { - if (g_strcasecmp(argv[2], "auto") == 0) + if (g_strcasecmp(argv[1], "xrdp") == 0) { - if (g_getuid() != 0) - { - g_writeln("must run as root"); - return 0; - } - return key_gen_auto(); + if (argc > 2) + { + if (g_strcasecmp(argv[2], "auto") == 0) + { + if (g_getuid() != 0) + { + g_writeln("must run as root"); + return 0; + } + + return key_gen_auto(); + } + else + { + return key_gen(argv[2]); + } + } + else + { + return key_gen(0); + } } - else + else if (g_strcasecmp(argv[1], "test") == 0) { - return key_gen(argv[2]); + return key_test(); } - } - else - { - return key_gen(0); - } } - else if (g_strcasecmp(argv[1], "test") == 0) - { - return key_test(); - } - } - out_params(); - return 0; + + out_params(); + return 0; } diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index 3f8307c2..a391b93b 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -1,672 +1,720 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - this is the interface to libxrdp - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * this is the interface to libxrdp + */ #include "libxrdp.h" /******************************************************************************/ -struct xrdp_session* EXPORT_CC -libxrdp_init(tbus id, struct trans* trans) +struct xrdp_session *EXPORT_CC +libxrdp_init(tbus id, struct trans *trans) { - struct xrdp_session* session; + struct xrdp_session *session; - session = (struct xrdp_session*)g_malloc(sizeof(struct xrdp_session), 1); - session->id = id; - session->rdp = xrdp_rdp_create(session, trans); - session->orders = xrdp_orders_create(session, (struct xrdp_rdp*)session->rdp); - session->client_info = &(((struct xrdp_rdp*)session->rdp)->client_info); - make_stream(session->s); - init_stream(session->s, 8192 * 2); - return session; + session = (struct xrdp_session *)g_malloc(sizeof(struct xrdp_session), 1); + session->id = id; + session->rdp = xrdp_rdp_create(session, trans); + session->orders = xrdp_orders_create(session, (struct xrdp_rdp *)session->rdp); + session->client_info = &(((struct xrdp_rdp *)session->rdp)->client_info); + make_stream(session->s); + init_stream(session->s, 8192 * 2); + return session; } /******************************************************************************/ int EXPORT_CC -libxrdp_exit(struct xrdp_session* session) +libxrdp_exit(struct xrdp_session *session) { - if (session == 0) - { + if (session == 0) + { + return 0; + } + + xrdp_orders_delete((struct xrdp_orders *)session->orders); + xrdp_rdp_delete((struct xrdp_rdp *)session->rdp); + free_stream(session->s); + g_free(session); return 0; - } - xrdp_orders_delete((struct xrdp_orders*)session->orders); - xrdp_rdp_delete((struct xrdp_rdp*)session->rdp); - free_stream(session->s); - g_free(session); - return 0; } /******************************************************************************/ int EXPORT_CC -libxrdp_disconnect(struct xrdp_session* session) +libxrdp_disconnect(struct xrdp_session *session) { - return xrdp_rdp_disconnect((struct xrdp_rdp*)session->rdp); + return xrdp_rdp_disconnect((struct xrdp_rdp *)session->rdp); } /******************************************************************************/ int EXPORT_CC -libxrdp_process_incomming(struct xrdp_session* session) +libxrdp_process_incomming(struct xrdp_session *session) { - return xrdp_rdp_incoming((struct xrdp_rdp*)session->rdp); + return xrdp_rdp_incoming((struct xrdp_rdp *)session->rdp); } /******************************************************************************/ int EXPORT_CC -libxrdp_process_data(struct xrdp_session* session) +libxrdp_process_data(struct xrdp_session *session) { - int cont; - int rv; - int code; - int term; - int dead_lock_counter; + int cont; + int rv; + int code; + int term; + int dead_lock_counter; - term = 0; - cont = 1; - rv = 0; - dead_lock_counter = 0; - while ((cont || !session->up_and_running) && !term) - { - if (session->is_term != 0) + term = 0; + cont = 1; + rv = 0; + dead_lock_counter = 0; + + while ((cont || !session->up_and_running) && !term) { - if (session->is_term()) - { - term = 1; - } - } - code = 0; - if (xrdp_rdp_recv((struct xrdp_rdp*)(session->rdp), - session->s, &code) != 0) - { - rv = 1; - break; - } - DEBUG(("libxrdp_process_data code %d", code)); - switch (code) - { - case -1: - xrdp_rdp_send_demand_active((struct xrdp_rdp*)session->rdp); - session->up_and_running = 0; - break; - case 0: - dead_lock_counter++; - break; - case RDP_PDU_CONFIRM_ACTIVE: /* 3 */ - xrdp_rdp_process_confirm_active((struct xrdp_rdp*)session->rdp, - session->s); - break; - case RDP_PDU_DATA: /* 7 */ - if (xrdp_rdp_process_data((struct xrdp_rdp*)session->rdp, - session->s) != 0) + if (session->is_term != 0) { - DEBUG(("libxrdp_process_data returned non zero")); - cont = 0; - term = 1; + if (session->is_term()) + { + term = 1; + } + } + + code = 0; + + if (xrdp_rdp_recv((struct xrdp_rdp *)(session->rdp), + session->s, &code) != 0) + { + rv = 1; + break; + } + + DEBUG(("libxrdp_process_data code %d", code)); + + switch (code) + { + case -1: + xrdp_rdp_send_demand_active((struct xrdp_rdp *)session->rdp); + session->up_and_running = 0; + break; + case 0: + dead_lock_counter++; + break; + case RDP_PDU_CONFIRM_ACTIVE: /* 3 */ + xrdp_rdp_process_confirm_active((struct xrdp_rdp *)session->rdp, + session->s); + break; + case RDP_PDU_DATA: /* 7 */ + + if (xrdp_rdp_process_data((struct xrdp_rdp *)session->rdp, + session->s) != 0) + { + DEBUG(("libxrdp_process_data returned non zero")); + cont = 0; + term = 1; + } + + break; + default: + g_writeln("unknown in libxrdp_process_data"); + dead_lock_counter++; + break; + } + + if (dead_lock_counter > 100000) + { + /*This situation can happen and this is a workaround*/ + cont = 0; + g_writeln("Serious programming error we were locked in a deadly loop") ; + g_writeln("remaining :%d", session->s->end - session->s->next_packet); + session->s->next_packet = 0; + } + + if (cont) + { + cont = (session->s->next_packet != 0) && + (session->s->next_packet < session->s->end); } - break; - default: - g_writeln("unknown in libxrdp_process_data"); - dead_lock_counter++; - break; } - if (dead_lock_counter > 100000) - { - /*This situation can happen and this is a workaround*/ - cont = 0; - g_writeln("Serious programming error we were locked in a deadly loop") ; - g_writeln("remaining :%d",session->s->end-session->s->next_packet); - session->s->next_packet = 0; - } - if (cont) - { - cont = (session->s->next_packet != 0) && - (session->s->next_packet < session->s->end); - } - } - return rv; + + return rv; } /******************************************************************************/ int EXPORT_CC -libxrdp_send_palette(struct xrdp_session* session, int* palette) +libxrdp_send_palette(struct xrdp_session *session, int *palette) { - int i = 0; - int color = 0; - struct stream* s = (struct stream *)NULL; + int i = 0; + int color = 0; + struct stream *s = (struct stream *)NULL; - if (session->client_info->bpp > 8) - { + if (session->client_info->bpp > 8) + { + return 0; + } + + DEBUG(("libxrdp_send_palette sending palette")); + /* clear orders */ + libxrdp_orders_force_send(session); + make_stream(s); + init_stream(s, 8192); + xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s); + out_uint16_le(s, RDP_UPDATE_PALETTE); + out_uint16_le(s, 0); + out_uint16_le(s, 256); /* # of colors */ + out_uint16_le(s, 0); + + for (i = 0; i < 256; i++) + { + color = palette[i]; + out_uint8(s, color >> 16); + out_uint8(s, color >> 8); + out_uint8(s, color); + } + + s_mark_end(s); + xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s, RDP_DATA_PDU_UPDATE); + free_stream(s); + /* send the orders palette too */ + libxrdp_orders_init(session); + libxrdp_orders_send_palette(session, palette, 0); + libxrdp_orders_send(session); return 0; - } - DEBUG(("libxrdp_send_palette sending palette")); - /* clear orders */ - libxrdp_orders_force_send(session); - make_stream(s); - init_stream(s, 8192); - xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); - out_uint16_le(s, RDP_UPDATE_PALETTE); - out_uint16_le(s, 0); - out_uint16_le(s, 256); /* # of colors */ - out_uint16_le(s, 0); - for (i = 0; i < 256; i++) - { - color = palette[i]; - out_uint8(s, color >> 16); - out_uint8(s, color >> 8); - out_uint8(s, color); - } - s_mark_end(s); - xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_UPDATE); - free_stream(s); - /* send the orders palette too */ - libxrdp_orders_init(session); - libxrdp_orders_send_palette(session, palette, 0); - libxrdp_orders_send(session); - return 0; } /******************************************************************************/ int EXPORT_CC -libxrdp_send_bell(struct xrdp_session* session) +libxrdp_send_bell(struct xrdp_session *session) { - struct stream* s = (struct stream *)NULL; + struct stream *s = (struct stream *)NULL; - DEBUG(("libxrdp_send_bell sending bell signal")); - /* see MS documentation: Server play sound PDU, TS_PLAY_SOUND_PDU_DATA */ + DEBUG(("libxrdp_send_bell sending bell signal")); + /* see MS documentation: Server play sound PDU, TS_PLAY_SOUND_PDU_DATA */ - make_stream(s); - init_stream(s, 8192); + make_stream(s); + init_stream(s, 8192); + + if (xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint32_le(s, 440); /* frequency */ + out_uint32_le(s, 100); /* duration (ms) */ + s_mark_end(s); + + if (xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s, RDP_DATA_PDU_PLAY_SOUND) != 0) + { + free_stream(s); + return 1; + } - if (xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s) != 0) - { free_stream(s); - return 1; - } - out_uint32_le(s, 440); /* frequency */ - out_uint32_le(s, 100); /* duration (ms) */ - s_mark_end(s); - if (xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_PLAY_SOUND) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; + return 0; } /*****************************************************************************/ int EXPORT_CC -libxrdp_send_bitmap(struct xrdp_session* session, int width, int height, - int bpp, char* data, int x, int y, int cx, int cy) +libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, + int bpp, char *data, int x, int y, int cx, int cy) { - int line_size = 0; - int i = 0; - int j = 0; - int total_lines = 0; - int lines_sending = 0; - int Bpp = 0; - int e = 0; - int bufsize = 0; - int total_bufsize = 0; - int num_updates = 0; - char* p_num_updates = (char *)NULL; - char* p = (char *)NULL; - char* q = (char *)NULL; - struct stream* s = (struct stream *)NULL; - struct stream* temp_s = (struct stream *)NULL; + int line_size = 0; + int i = 0; + int j = 0; + int total_lines = 0; + int lines_sending = 0; + int Bpp = 0; + int e = 0; + int bufsize = 0; + int total_bufsize = 0; + int num_updates = 0; + char *p_num_updates = (char *)NULL; + char *p = (char *)NULL; + char *q = (char *)NULL; + struct stream *s = (struct stream *)NULL; + struct stream *temp_s = (struct stream *)NULL; - DEBUG(("libxrdp_send_bitmap sending bitmap")); - Bpp = (bpp + 7) / 8; - e = width % 4; - if (e != 0) - { - e = 4 - e; - } - line_size = width * Bpp; - make_stream(s); - init_stream(s, 8192); - if (session->client_info->use_bitmap_comp) - { - make_stream(temp_s); - init_stream(temp_s, 65536); - i = 0; - if (cy <= height) + DEBUG(("libxrdp_send_bitmap sending bitmap")); + Bpp = (bpp + 7) / 8; + e = width % 4; + + if (e != 0) { - i = cy; + e = 4 - e; } - while (i > 0) + + line_size = width * Bpp; + make_stream(s); + init_stream(s, 8192); + + if (session->client_info->use_bitmap_comp) { - total_bufsize = 0; - num_updates = 0; - xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); - out_uint16_le(s, RDP_UPDATE_BITMAP); - p_num_updates = s->p; - out_uint8s(s, 2); /* num_updates set later */ - do - { - if (session->client_info->op1) + make_stream(temp_s); + init_stream(temp_s, 65536); + i = 0; + + if (cy <= height) { - s_push_layer(s, channel_hdr, 18); + i = cy; } - else + + while (i > 0) { - s_push_layer(s, channel_hdr, 26); + total_bufsize = 0; + num_updates = 0; + xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s); + out_uint16_le(s, RDP_UPDATE_BITMAP); + p_num_updates = s->p; + out_uint8s(s, 2); /* num_updates set later */ + + do + { + if (session->client_info->op1) + { + s_push_layer(s, channel_hdr, 18); + } + else + { + s_push_layer(s, channel_hdr, 26); + } + + p = s->p; + lines_sending = xrdp_bitmap_compress(data, width, height, + s, bpp, + 4096 - total_bufsize, + i - 1, temp_s, e); + + if (lines_sending == 0) + { + break; + } + + num_updates++; + bufsize = s->p - p; + total_bufsize += bufsize; + i = i - lines_sending; + s_mark_end(s); + s_pop_layer(s, channel_hdr); + out_uint16_le(s, x); /* left */ + out_uint16_le(s, y + i); /* top */ + out_uint16_le(s, (x + cx) - 1); /* right */ + out_uint16_le(s, (y + i + lines_sending) - 1); /* bottom */ + out_uint16_le(s, width + e); /* width */ + out_uint16_le(s, lines_sending); /* height */ + out_uint16_le(s, bpp); /* bpp */ + + if (session->client_info->op1) + { + out_uint16_le(s, 0x401); /* compress */ + out_uint16_le(s, bufsize); /* compressed size */ + j = (width + e) * Bpp; + j = j * lines_sending; + } + else + { + out_uint16_le(s, 0x1); /* compress */ + out_uint16_le(s, bufsize + 8); + out_uint8s(s, 2); /* pad */ + out_uint16_le(s, bufsize); /* compressed size */ + j = (width + e) * Bpp; + out_uint16_le(s, j); /* line size */ + j = j * lines_sending; + out_uint16_le(s, j); /* final size */ + } + + if (j > 32768) + { + g_writeln("error, decompressed size too big, its %d", j); + } + + if (bufsize > 8192) + { + g_writeln("error, compressed size too big, its %d", bufsize); + } + + s->p = s->end; + } + while (total_bufsize < 4096 && i > 0); + + p_num_updates[0] = num_updates; + p_num_updates[1] = num_updates >> 8; + xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s, + RDP_DATA_PDU_UPDATE); + + if (total_bufsize > 8192) + { + g_writeln("error, total compressed size too big, its %d", + total_bufsize); + } } - p = s->p; - lines_sending = xrdp_bitmap_compress(data, width, height, - s, bpp, - 4096 - total_bufsize, - i - 1, temp_s, e); - if (lines_sending == 0) - { - break; - } - num_updates++; - bufsize = s->p - p; - total_bufsize += bufsize; - i = i - lines_sending; - s_mark_end(s); - s_pop_layer(s, channel_hdr); - out_uint16_le(s, x); /* left */ - out_uint16_le(s, y + i); /* top */ - out_uint16_le(s, (x + cx) - 1); /* right */ - out_uint16_le(s, (y + i + lines_sending) - 1); /* bottom */ - out_uint16_le(s, width + e); /* width */ - out_uint16_le(s, lines_sending); /* height */ - out_uint16_le(s, bpp); /* bpp */ - if (session->client_info->op1) - { - out_uint16_le(s, 0x401); /* compress */ - out_uint16_le(s, bufsize); /* compressed size */ - j = (width + e) * Bpp; - j = j * lines_sending; - } - else - { - out_uint16_le(s, 0x1); /* compress */ - out_uint16_le(s, bufsize + 8); - out_uint8s(s, 2); /* pad */ - out_uint16_le(s, bufsize); /* compressed size */ - j = (width + e) * Bpp; - out_uint16_le(s, j); /* line size */ - j = j * lines_sending; - out_uint16_le(s, j); /* final size */ - } - if (j > 32768) - { - g_writeln("error, decompressed size too big, its %d", j); - } - if (bufsize > 8192) - { - g_writeln("error, compressed size too big, its %d", bufsize); - } - s->p = s->end; - } while (total_bufsize < 4096 && i > 0); - p_num_updates[0] = num_updates; - p_num_updates[1] = num_updates >> 8; - xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, - RDP_DATA_PDU_UPDATE); - if (total_bufsize > 8192) - { - g_writeln("error, total compressed size too big, its %d", - total_bufsize); - } + + free_stream(temp_s); } - free_stream(temp_s); - } - else - { - total_lines = height; - i = 0; + else + { + total_lines = height; + i = 0; + p = data; + + if (line_size > 0 && total_lines > 0) + { + while (i < total_lines) + { + lines_sending = 4096 / (line_size + e * Bpp); + + if (i + lines_sending > total_lines) + { + lines_sending = total_lines - i; + } + + p = p + line_size * lines_sending; + xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s); + out_uint16_le(s, RDP_UPDATE_BITMAP); + out_uint16_le(s, 1); /* num updates */ + out_uint16_le(s, x); + out_uint16_le(s, y + i); + out_uint16_le(s, (x + cx) - 1); + out_uint16_le(s, (y + i + lines_sending) - 1); + out_uint16_le(s, width + e); + out_uint16_le(s, lines_sending); + out_uint16_le(s, bpp); /* bpp */ + out_uint16_le(s, 0); /* compress */ + out_uint16_le(s, (line_size + e * Bpp) * lines_sending); /* bufsize */ + q = p; + + for (j = 0; j < lines_sending; j++) + { + q = q - line_size; + out_uint8a(s, q, line_size); /* B_ENDIAN doesn't work here, todo */ + out_uint8s(s, e * Bpp); + } + + s_mark_end(s); + xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s, + RDP_DATA_PDU_UPDATE); + i = i + lines_sending; + } + } + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_send_pointer(struct xrdp_session *session, int cache_idx, + char *data, char *mask, int x, int y) +{ + struct stream *s; + char *p; + int i; + int j; + + DEBUG(("libxrdp_send_pointer sending cursor")); + make_stream(s); + init_stream(s, 8192); + xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s); + out_uint16_le(s, RDP_POINTER_COLOR); + out_uint16_le(s, 0); /* pad */ + out_uint16_le(s, cache_idx); /* cache_idx */ + out_uint16_le(s, x); + out_uint16_le(s, y); + out_uint16_le(s, 32); + out_uint16_le(s, 32); + out_uint16_le(s, 128); + out_uint16_le(s, 3072); p = data; - if (line_size > 0 && total_lines > 0) + + for (i = 0; i < 32; i++) { - while (i < total_lines) - { - lines_sending = 4096 / (line_size + e * Bpp); - if (i + lines_sending > total_lines) + for (j = 0; j < 32; j++) { - lines_sending = total_lines - i; + out_uint8(s, *p); + p++; + out_uint8(s, *p); + p++; + out_uint8(s, *p); + p++; } - p = p + line_size * lines_sending; - xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); - out_uint16_le(s, RDP_UPDATE_BITMAP); - out_uint16_le(s, 1); /* num updates */ - out_uint16_le(s, x); - out_uint16_le(s, y + i); - out_uint16_le(s, (x + cx) - 1); - out_uint16_le(s, (y + i + lines_sending) - 1); - out_uint16_le(s, width + e); - out_uint16_le(s, lines_sending); - out_uint16_le(s, bpp); /* bpp */ - out_uint16_le(s, 0); /* compress */ - out_uint16_le(s, (line_size + e * Bpp) * lines_sending); /* bufsize */ - q = p; - for (j = 0; j < lines_sending; j++) - { - q = q - line_size; - out_uint8a(s, q, line_size); /* B_ENDIAN doesn't work here, todo */ - out_uint8s(s, e * Bpp); - } - s_mark_end(s); - xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, - RDP_DATA_PDU_UPDATE); - i = i + lines_sending; - } } - } - free_stream(s); - return 0; + + out_uint8a(s, mask, 128); /* mask */ + s_mark_end(s); + xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s, RDP_DATA_PDU_POINTER); + free_stream(s); + return 0; } /*****************************************************************************/ int EXPORT_CC -libxrdp_send_pointer(struct xrdp_session* session, int cache_idx, - char* data, char* mask, int x, int y) +libxrdp_set_pointer(struct xrdp_session *session, int cache_idx) { - struct stream* s; - char* p; - int i; - int j; + struct stream *s; - DEBUG(("libxrdp_send_pointer sending cursor")); - make_stream(s); - init_stream(s, 8192); - xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); - out_uint16_le(s, RDP_POINTER_COLOR); - out_uint16_le(s, 0); /* pad */ - out_uint16_le(s, cache_idx); /* cache_idx */ - out_uint16_le(s, x); - out_uint16_le(s, y); - out_uint16_le(s, 32); - out_uint16_le(s, 32); - out_uint16_le(s, 128); - out_uint16_le(s, 3072); - p = data; - for (i = 0; i < 32; i++) - { - for (j = 0; j < 32; j++) - { - out_uint8(s, *p); - p++; - out_uint8(s, *p); - p++; - out_uint8(s, *p); - p++; - } - } - out_uint8a(s, mask, 128); /* mask */ - s_mark_end(s); - xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_POINTER); - free_stream(s); - return 0; -} - -/*****************************************************************************/ -int EXPORT_CC -libxrdp_set_pointer(struct xrdp_session* session, int cache_idx) -{ - struct stream* s; - - DEBUG(("libxrdp_set_pointer sending cursor index")); - make_stream(s); - init_stream(s, 8192); - xrdp_rdp_init_data((struct xrdp_rdp*)session->rdp, s); - out_uint16_le(s, RDP_POINTER_CACHED); - out_uint16_le(s, 0); /* pad */ - out_uint16_le(s, cache_idx); /* cache_idx */ - s_mark_end(s); - xrdp_rdp_send_data((struct xrdp_rdp*)session->rdp, s, RDP_DATA_PDU_POINTER); - free_stream(s); - return 0; + DEBUG(("libxrdp_set_pointer sending cursor index")); + make_stream(s); + init_stream(s, 8192); + xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s); + out_uint16_le(s, RDP_POINTER_CACHED); + out_uint16_le(s, 0); /* pad */ + out_uint16_le(s, cache_idx); /* cache_idx */ + s_mark_end(s); + xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s, RDP_DATA_PDU_POINTER); + free_stream(s); + return 0; } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_init(struct xrdp_session* session) +libxrdp_orders_init(struct xrdp_session *session) { - return xrdp_orders_init((struct xrdp_orders*)session->orders); + return xrdp_orders_init((struct xrdp_orders *)session->orders); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_send(struct xrdp_session* session) +libxrdp_orders_send(struct xrdp_session *session) { - return xrdp_orders_send((struct xrdp_orders*)session->orders); + return xrdp_orders_send((struct xrdp_orders *)session->orders); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_force_send(struct xrdp_session* session) +libxrdp_orders_force_send(struct xrdp_session *session) { - return xrdp_orders_force_send((struct xrdp_orders*)session->orders); + return xrdp_orders_force_send((struct xrdp_orders *)session->orders); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_rect(struct xrdp_session* session, int x, int y, - int cx, int cy, int color, struct xrdp_rect* rect) +libxrdp_orders_rect(struct xrdp_session *session, int x, int y, + int cx, int cy, int color, struct xrdp_rect *rect) { - return xrdp_orders_rect((struct xrdp_orders*)session->orders, - x, y, cx, cy, color, rect); + return xrdp_orders_rect((struct xrdp_orders *)session->orders, + x, y, cx, cy, color, rect); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_screen_blt(struct xrdp_session* session, int x, int y, +libxrdp_orders_screen_blt(struct xrdp_session *session, int x, int y, int cx, int cy, int srcx, int srcy, - int rop, struct xrdp_rect* rect) + int rop, struct xrdp_rect *rect) { - return xrdp_orders_screen_blt((struct xrdp_orders*)session->orders, - x, y, cx, cy, srcx, srcy, rop, rect); + return xrdp_orders_screen_blt((struct xrdp_orders *)session->orders, + x, y, cx, cy, srcx, srcy, rop, rect); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_pat_blt(struct xrdp_session* session, int x, int y, +libxrdp_orders_pat_blt(struct xrdp_session *session, int x, int y, int cx, int cy, int rop, int bg_color, - int fg_color, struct xrdp_brush* brush, - struct xrdp_rect* rect) + int fg_color, struct xrdp_brush *brush, + struct xrdp_rect *rect) { - return xrdp_orders_pat_blt((struct xrdp_orders*)session->orders, - x, y, cx, cy, rop, bg_color, fg_color, - brush, rect); + return xrdp_orders_pat_blt((struct xrdp_orders *)session->orders, + x, y, cx, cy, rop, bg_color, fg_color, + brush, rect); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_dest_blt(struct xrdp_session* session, int x, int y, +libxrdp_orders_dest_blt(struct xrdp_session *session, int x, int y, int cx, int cy, int rop, - struct xrdp_rect* rect) + struct xrdp_rect *rect) { - return xrdp_orders_dest_blt((struct xrdp_orders*)session->orders, - x, y, cx, cy, rop, rect); + return xrdp_orders_dest_blt((struct xrdp_orders *)session->orders, + x, y, cx, cy, rop, rect); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_line(struct xrdp_session* session, int mix_mode, +libxrdp_orders_line(struct xrdp_session *session, int mix_mode, int startx, int starty, int endx, int endy, int rop, int bg_color, - struct xrdp_pen* pen, - struct xrdp_rect* rect) + struct xrdp_pen *pen, + struct xrdp_rect *rect) { - return xrdp_orders_line((struct xrdp_orders*)session->orders, - mix_mode, startx, starty, endx, endy, - rop, bg_color, pen, rect); + return xrdp_orders_line((struct xrdp_orders *)session->orders, + mix_mode, startx, starty, endx, endy, + rop, bg_color, pen, rect); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_mem_blt(struct xrdp_session* session, int cache_id, +libxrdp_orders_mem_blt(struct xrdp_session *session, int cache_id, int color_table, int x, int y, int cx, int cy, int rop, int srcx, int srcy, - int cache_idx, struct xrdp_rect* rect) + int cache_idx, struct xrdp_rect *rect) { - return xrdp_orders_mem_blt((struct xrdp_orders*)session->orders, - cache_id, color_table, x, y, cx, cy, rop, - srcx, srcy, cache_idx, rect); + return xrdp_orders_mem_blt((struct xrdp_orders *)session->orders, + cache_id, color_table, x, y, cx, cy, rop, + srcx, srcy, cache_idx, rect); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_text(struct xrdp_session* session, +libxrdp_orders_text(struct xrdp_session *session, int font, int flags, int mixmode, int fg_color, int bg_color, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, - int x, int y, char* data, int data_len, - struct xrdp_rect* rect) + int x, int y, char *data, int data_len, + struct xrdp_rect *rect) { - return xrdp_orders_text((struct xrdp_orders*)session->orders, - font, flags, mixmode, fg_color, bg_color, - clip_left, clip_top, clip_right, clip_bottom, - box_left, box_top, box_right, box_bottom, - x, y, data, data_len, rect); + return xrdp_orders_text((struct xrdp_orders *)session->orders, + font, flags, mixmode, fg_color, bg_color, + clip_left, clip_top, clip_right, clip_bottom, + box_left, box_top, box_right, box_bottom, + x, y, data, data_len, rect); } /******************************************************************************/ int EXPORT_CC -libxrdp_orders_send_palette(struct xrdp_session* session, int* palette, +libxrdp_orders_send_palette(struct xrdp_session *session, int *palette, int cache_id) { - return xrdp_orders_send_palette((struct xrdp_orders*)session->orders, - palette, cache_id); + return xrdp_orders_send_palette((struct xrdp_orders *)session->orders, + palette, cache_id); } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_raw_bitmap(struct xrdp_session* session, - int width, int height, int bpp, char* data, +libxrdp_orders_send_raw_bitmap(struct xrdp_session *session, + int width, int height, int bpp, char *data, int cache_id, int cache_idx) { - return xrdp_orders_send_raw_bitmap((struct xrdp_orders*)session->orders, - width, height, bpp, data, - cache_id, cache_idx); + return xrdp_orders_send_raw_bitmap((struct xrdp_orders *)session->orders, + width, height, bpp, data, + cache_id, cache_idx); } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_bitmap(struct xrdp_session* session, - int width, int height, int bpp, char* data, +libxrdp_orders_send_bitmap(struct xrdp_session *session, + int width, int height, int bpp, char *data, int cache_id, int cache_idx) { - return xrdp_orders_send_bitmap((struct xrdp_orders*)session->orders, - width, height, bpp, data, - cache_id, cache_idx); + return xrdp_orders_send_bitmap((struct xrdp_orders *)session->orders, + width, height, bpp, data, + cache_id, cache_idx); } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_font(struct xrdp_session* session, - struct xrdp_font_char* font_char, +libxrdp_orders_send_font(struct xrdp_session *session, + struct xrdp_font_char *font_char, int font_index, int char_index) { - return xrdp_orders_send_font((struct xrdp_orders*)session->orders, - font_char, font_index, char_index); + return xrdp_orders_send_font((struct xrdp_orders *)session->orders, + font_char, font_index, char_index); } /*****************************************************************************/ int EXPORT_CC -libxrdp_reset(struct xrdp_session* session, +libxrdp_reset(struct xrdp_session *session, int width, int height, int bpp) { - if (session->client_info != 0) - { - /* older client can't resize */ - if (session->client_info->build <= 419) + if (session->client_info != 0) { - return 0; + /* older client can't resize */ + if (session->client_info->build <= 419) + { + return 0; + } + + /* if same, don't need to do anything */ + if (session->client_info->width == width && + session->client_info->height == height && + session->client_info->bpp == bpp) + { + return 0; + } + + session->client_info->width = width; + session->client_info->height = height; + session->client_info->bpp = bpp; } - /* if same, don't need to do anything */ - if (session->client_info->width == width && - session->client_info->height == height && - session->client_info->bpp == bpp) + else { - return 0; + return 1; } - session->client_info->width = width; - session->client_info->height = height; - session->client_info->bpp = bpp; - } - else - { - return 1; - } - /* this will send any lingering orders */ - if (xrdp_orders_reset((struct xrdp_orders*)session->orders) != 0) - { - return 1; - } - /* shut down the rdp client */ - if (xrdp_rdp_send_deactive((struct xrdp_rdp*)session->rdp) != 0) - { - return 1; - } - /* this should do the resizing */ - if (xrdp_rdp_send_demand_active((struct xrdp_rdp*)session->rdp) != 0) - { - return 1; - } - /* process till up and running */ - session->up_and_running = 0; - if (libxrdp_process_data(session) != 0) - { - g_writeln("non handled error from libxrdp_process_data"); - } - return 0; + + /* this will send any lingering orders */ + if (xrdp_orders_reset((struct xrdp_orders *)session->orders) != 0) + { + return 1; + } + + /* shut down the rdp client */ + if (xrdp_rdp_send_deactive((struct xrdp_rdp *)session->rdp) != 0) + { + return 1; + } + + /* this should do the resizing */ + if (xrdp_rdp_send_demand_active((struct xrdp_rdp *)session->rdp) != 0) + { + return 1; + } + + /* process till up and running */ + session->up_and_running = 0; + + if (libxrdp_process_data(session) != 0) + { + g_writeln("non handled error from libxrdp_process_data"); + } + + return 0; } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_raw_bitmap2(struct xrdp_session* session, - int width, int height, int bpp, char* data, +libxrdp_orders_send_raw_bitmap2(struct xrdp_session *session, + int width, int height, int bpp, char *data, int cache_id, int cache_idx) { - return xrdp_orders_send_raw_bitmap2((struct xrdp_orders*)session->orders, - width, height, bpp, data, - cache_id, cache_idx); + return xrdp_orders_send_raw_bitmap2((struct xrdp_orders *)session->orders, + width, height, bpp, data, + cache_id, cache_idx); } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_bitmap2(struct xrdp_session* session, - int width, int height, int bpp, char* data, +libxrdp_orders_send_bitmap2(struct xrdp_session *session, + int width, int height, int bpp, char *data, int cache_id, int cache_idx, int hints) { - return xrdp_orders_send_bitmap2((struct xrdp_orders*)session->orders, - width, height, bpp, data, - cache_id, cache_idx, hints); + return xrdp_orders_send_bitmap2((struct xrdp_orders *)session->orders, + width, height, bpp, data, + cache_id, cache_idx, hints); } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_bitmap3(struct xrdp_session* session, - int width, int height, int bpp, char* data, +libxrdp_orders_send_bitmap3(struct xrdp_session *session, + int width, int height, int bpp, char *data, int cache_id, int cache_idx, int hints) { - return xrdp_orders_send_bitmap3((struct xrdp_orders*)session->orders, - width, height, bpp, data, - cache_id, cache_idx, hints); + return xrdp_orders_send_bitmap3((struct xrdp_orders *)session->orders, + width, height, bpp, data, + cache_id, cache_idx, hints); } /*****************************************************************************/ @@ -675,226 +723,243 @@ libxrdp_orders_send_bitmap3(struct xrdp_session* session, based. either channel_name or channel_flags can be passed in nil if they are not needed */ int EXPORT_CC -libxrdp_query_channel(struct xrdp_session* session, int index, - char* channel_name, int* channel_flags) +libxrdp_query_channel(struct xrdp_session *session, int index, + char *channel_name, int *channel_flags) { - int count = 0; - struct xrdp_rdp* rdp = (struct xrdp_rdp *)NULL; - struct xrdp_mcs* mcs = (struct xrdp_mcs *)NULL; - struct mcs_channel_item* channel_item = (struct mcs_channel_item *)NULL; + int count = 0; + struct xrdp_rdp *rdp = (struct xrdp_rdp *)NULL; + struct xrdp_mcs *mcs = (struct xrdp_mcs *)NULL; + struct mcs_channel_item *channel_item = (struct mcs_channel_item *)NULL; - rdp = (struct xrdp_rdp*)session->rdp; - mcs = rdp->sec_layer->mcs_layer; - if (mcs->channel_list == NULL) - { - g_writeln("libxrdp_query_channel - No channel initialized"); - return 1 ; - } - count = mcs->channel_list->count; - if (index < 0 || index >= count) - { - return 1; - } - channel_item = (struct mcs_channel_item*) - list_get_item(mcs->channel_list, index); - if (channel_item == 0) - { - /* this should not happen */ - g_writeln("libxrdp_query_channel - channel item is 0"); - return 1; - } - if (channel_name != 0) - { - g_strncpy(channel_name, channel_item->name, 8); - } - if (channel_flags != 0) - { - *channel_flags = channel_item->flags; - } - return 0; + rdp = (struct xrdp_rdp *)session->rdp; + mcs = rdp->sec_layer->mcs_layer; + + if (mcs->channel_list == NULL) + { + g_writeln("libxrdp_query_channel - No channel initialized"); + return 1 ; + } + + count = mcs->channel_list->count; + + if (index < 0 || index >= count) + { + return 1; + } + + channel_item = (struct mcs_channel_item *) + list_get_item(mcs->channel_list, index); + + if (channel_item == 0) + { + /* this should not happen */ + g_writeln("libxrdp_query_channel - channel item is 0"); + return 1; + } + + if (channel_name != 0) + { + g_strncpy(channel_name, channel_item->name, 8); + } + + if (channel_flags != 0) + { + *channel_flags = channel_item->flags; + } + + return 0; } /*****************************************************************************/ /* returns a zero based index of the channel, -1 if error or it dosen't exist */ int EXPORT_CC -libxrdp_get_channel_id(struct xrdp_session* session, char* name) +libxrdp_get_channel_id(struct xrdp_session *session, char *name) { - int index = 0; - int count = 0; - struct xrdp_rdp* rdp = NULL; - struct xrdp_mcs* mcs = NULL; - struct mcs_channel_item* channel_item = NULL; + int index = 0; + int count = 0; + struct xrdp_rdp *rdp = NULL; + struct xrdp_mcs *mcs = NULL; + struct mcs_channel_item *channel_item = NULL; - rdp = (struct xrdp_rdp*)session->rdp; - mcs = rdp->sec_layer->mcs_layer; - if (mcs->channel_list == NULL) - { - g_writeln("libxrdp_get_channel_id No channel initialized"); - return -1 ; - } - count = mcs->channel_list->count; - for (index = 0; index < count; index++) - { - channel_item = (struct mcs_channel_item*) - list_get_item(mcs->channel_list, index); - if (channel_item != 0) + rdp = (struct xrdp_rdp *)session->rdp; + mcs = rdp->sec_layer->mcs_layer; + + if (mcs->channel_list == NULL) { - if (g_strcasecmp(name, channel_item->name) == 0) - { - return index; - } + g_writeln("libxrdp_get_channel_id No channel initialized"); + return -1 ; } - } - return -1; + + count = mcs->channel_list->count; + + for (index = 0; index < count; index++) + { + channel_item = (struct mcs_channel_item *) + list_get_item(mcs->channel_list, index); + + if (channel_item != 0) + { + if (g_strcasecmp(name, channel_item->name) == 0) + { + return index; + } + } + } + + return -1; } /*****************************************************************************/ int EXPORT_CC -libxrdp_send_to_channel(struct xrdp_session* session, int channel_id, - char* data, int data_len, +libxrdp_send_to_channel(struct xrdp_session *session, int channel_id, + char *data, int data_len, int total_data_len, int flags) { - struct xrdp_rdp* rdp = NULL; - struct xrdp_sec* sec = NULL; - struct xrdp_channel* chan = NULL; - struct stream* s = NULL; + struct xrdp_rdp *rdp = NULL; + struct xrdp_sec *sec = NULL; + struct xrdp_channel *chan = NULL; + struct stream *s = NULL; + + rdp = (struct xrdp_rdp *)session->rdp; + sec = rdp->sec_layer; + chan = sec->chan_layer; + make_stream(s); + init_stream(s, data_len + 1024); /* this should be big enough */ + + if (xrdp_channel_init(chan, s) != 0) + { + free_stream(s); + return 1; + } + + /* here we make a copy of the data */ + out_uint8a(s, data, data_len); + s_mark_end(s); + + if (xrdp_channel_send(chan, s, channel_id, total_data_len, flags) != 0) + { + g_writeln("Debug - data NOT sent to channel"); + free_stream(s); + return 1; + } - rdp = (struct xrdp_rdp*)session->rdp; - sec = rdp->sec_layer; - chan = sec->chan_layer; - make_stream(s); - init_stream(s, data_len + 1024); /* this should be big enough */ - if (xrdp_channel_init(chan, s) != 0) - { free_stream(s); - return 1; - } - /* here we make a copy of the data */ - out_uint8a(s, data, data_len); - s_mark_end(s); - if (xrdp_channel_send(chan, s, channel_id, total_data_len, flags) != 0) - { - g_writeln("Debug - data NOT sent to channel"); - free_stream(s); - return 1; - } - free_stream(s); - return 0; + return 0; } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_brush(struct xrdp_session* session, +libxrdp_orders_send_brush(struct xrdp_session *session, int width, int height, int bpp, int type, - int size, char* data, int cache_id) + int size, char *data, int cache_id) { - return xrdp_orders_send_brush((struct xrdp_orders*)session->orders, - width, height, bpp, type, size, data, - cache_id); + return xrdp_orders_send_brush((struct xrdp_orders *)session->orders, + width, height, bpp, type, size, data, + cache_id); } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_create_os_surface(struct xrdp_session* session, int id, +libxrdp_orders_send_create_os_surface(struct xrdp_session *session, int id, int width, int height, - struct list* del_list) + struct list *del_list) { - return xrdp_orders_send_create_os_surface - ((struct xrdp_orders*)(session->orders), id, - width, height, del_list); + return xrdp_orders_send_create_os_surface + ((struct xrdp_orders *)(session->orders), id, + width, height, del_list); } /*****************************************************************************/ int EXPORT_CC -libxrdp_orders_send_switch_os_surface(struct xrdp_session* session, int id) +libxrdp_orders_send_switch_os_surface(struct xrdp_session *session, int id) { - return xrdp_orders_send_switch_os_surface - ((struct xrdp_orders*)(session->orders), id); + return xrdp_orders_send_switch_os_surface + ((struct xrdp_orders *)(session->orders), id); } /*****************************************************************************/ int EXPORT_CC -libxrdp_window_new_update(struct xrdp_session* session, int window_id, - struct rail_window_state_order* window_state, +libxrdp_window_new_update(struct xrdp_session *session, int window_id, + struct rail_window_state_order *window_state, int flags) { - struct xrdp_orders* orders; + struct xrdp_orders *orders; - orders = (struct xrdp_orders*)(session->orders); - return xrdp_orders_send_window_new_update(orders, window_id, - window_state, flags); + orders = (struct xrdp_orders *)(session->orders); + return xrdp_orders_send_window_new_update(orders, window_id, + window_state, flags); } /*****************************************************************************/ int EXPORT_CC -libxrdp_window_delete(struct xrdp_session* session, int window_id) +libxrdp_window_delete(struct xrdp_session *session, int window_id) { - struct xrdp_orders* orders; + struct xrdp_orders *orders; - orders = (struct xrdp_orders*)(session->orders); - return xrdp_orders_send_window_delete(orders, window_id); + orders = (struct xrdp_orders *)(session->orders); + return xrdp_orders_send_window_delete(orders, window_id); } /*****************************************************************************/ int EXPORT_CC -libxrdp_window_icon(struct xrdp_session* session, int window_id, +libxrdp_window_icon(struct xrdp_session *session, int window_id, int cache_entry, int cache_id, - struct rail_icon_info* icon_info, int flags) + struct rail_icon_info *icon_info, int flags) { - struct xrdp_orders* orders; + struct xrdp_orders *orders; - orders = (struct xrdp_orders*)(session->orders); - return xrdp_orders_send_window_icon(orders, window_id, cache_entry, - cache_id, icon_info, flags); + orders = (struct xrdp_orders *)(session->orders); + return xrdp_orders_send_window_icon(orders, window_id, cache_entry, + cache_id, icon_info, flags); } /*****************************************************************************/ int EXPORT_CC -libxrdp_window_cached_icon(struct xrdp_session* session, int window_id, +libxrdp_window_cached_icon(struct xrdp_session *session, int window_id, int cache_entry, int cache_id, int flags) { - struct xrdp_orders* orders; + struct xrdp_orders *orders; - orders = (struct xrdp_orders*)(session->orders); - return xrdp_orders_send_window_cached_icon(orders, window_id, cache_entry, - cache_id, flags); + orders = (struct xrdp_orders *)(session->orders); + return xrdp_orders_send_window_cached_icon(orders, window_id, cache_entry, + cache_id, flags); } /*****************************************************************************/ int EXPORT_CC -libxrdp_notify_new_update(struct xrdp_session* session, +libxrdp_notify_new_update(struct xrdp_session *session, int window_id, int notify_id, - struct rail_notify_state_order* notify_state, + struct rail_notify_state_order *notify_state, int flags) { - struct xrdp_orders* orders; + struct xrdp_orders *orders; - orders = (struct xrdp_orders*)(session->orders); - return xrdp_orders_send_notify_new_update(orders, window_id, notify_id, - notify_state, flags); + orders = (struct xrdp_orders *)(session->orders); + return xrdp_orders_send_notify_new_update(orders, window_id, notify_id, + notify_state, flags); } /*****************************************************************************/ int DEFAULT_CC -libxrdp_notify_delete(struct xrdp_session* session, +libxrdp_notify_delete(struct xrdp_session *session, int window_id, int notify_id) { - struct xrdp_orders* orders; + struct xrdp_orders *orders; - orders = (struct xrdp_orders*)(session->orders); - return xrdp_orders_send_notify_delete(orders, window_id, notify_id); + orders = (struct xrdp_orders *)(session->orders); + return xrdp_orders_send_notify_delete(orders, window_id, notify_id); } /*****************************************************************************/ int DEFAULT_CC -libxrdp_monitored_desktop(struct xrdp_session* session, - struct rail_monitored_desktop_order* mdo, +libxrdp_monitored_desktop(struct xrdp_session *session, + struct rail_monitored_desktop_order *mdo, int flags) { - struct xrdp_orders* orders; + struct xrdp_orders *orders; - orders = (struct xrdp_orders*)(session->orders); - return xrdp_orders_send_monitored_desktop(orders, mdo, flags); + orders = (struct xrdp_orders *)(session->orders); + return xrdp_orders_send_monitored_desktop(orders, mdo, flags); } diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h index b066db95..34924715 100644 --- a/libxrdp/libxrdp.h +++ b/libxrdp/libxrdp.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - libxrdp header - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2010 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * libxrdp header + */ #if !defined(LIBXRDP_H) #define LIBXRDP_H diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index 4f3504e6..ebfc348c 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - header file for use with libxrdp.so / xrdp.dll - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2010 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * header file for use with libxrdp.so / xrdp.dll + */ #ifndef LIBXRDPINC_H #define LIBXRDPINC_H diff --git a/libxrdp/xrdp_bitmap_compress.c b/libxrdp/xrdp_bitmap_compress.c index fcaab1f7..87538450 100644 --- a/libxrdp/xrdp_bitmap_compress.c +++ b/libxrdp/xrdp_bitmap_compress.c @@ -1,1474 +1,1570 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - bitmap compressor - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * bitmap compressor + */ #include "libxrdp.h" /*****************************************************************************/ #define IN_PIXEL8(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ -{ \ - if (in_ptr == 0) \ - { \ - in_pixel = 0; \ - } \ - else if (in_x < in_w) \ - { \ - in_pixel = GETPIXEL8(in_ptr, in_x, in_y, in_w); \ - } \ - else \ - { \ - in_pixel = in_last_pixel; \ - } \ -} + { \ + if (in_ptr == 0) \ + { \ + in_pixel = 0; \ + } \ + else if (in_x < in_w) \ + { \ + in_pixel = GETPIXEL8(in_ptr, in_x, in_y, in_w); \ + } \ + else \ + { \ + in_pixel = in_last_pixel; \ + } \ + } /*****************************************************************************/ #define IN_PIXEL16(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ -{ \ - if (in_ptr == 0) \ - { \ - in_pixel = 0; \ - } \ - else if (in_x < in_w) \ - { \ - in_pixel = GETPIXEL16(in_ptr, in_x, in_y, in_w); \ - } \ - else \ - { \ - in_pixel = in_last_pixel; \ - } \ -} + { \ + if (in_ptr == 0) \ + { \ + in_pixel = 0; \ + } \ + else if (in_x < in_w) \ + { \ + in_pixel = GETPIXEL16(in_ptr, in_x, in_y, in_w); \ + } \ + else \ + { \ + in_pixel = in_last_pixel; \ + } \ + } /*****************************************************************************/ #define IN_PIXEL32(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ -{ \ - if (in_ptr == 0) \ - { \ - in_pixel = 0; \ - } \ - else if (in_x < in_w) \ - { \ - in_pixel = GETPIXEL32(in_ptr, in_x, in_y, in_w); \ - } \ - else \ - { \ - in_pixel = in_last_pixel; \ - } \ -} + { \ + if (in_ptr == 0) \ + { \ + in_pixel = 0; \ + } \ + else if (in_x < in_w) \ + { \ + in_pixel = GETPIXEL32(in_ptr, in_x, in_y, in_w); \ + } \ + else \ + { \ + in_pixel = in_last_pixel; \ + } \ + } /*****************************************************************************/ /* color */ #define OUT_COLOR_COUNT1(in_count, in_s, in_data) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x3 << 5) | in_count; \ - out_uint8(in_s, temp); \ - out_uint8(in_s, in_data); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x60); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - out_uint8(in_s, in_data); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf3); \ - out_uint16_le(in_s, in_count); \ - out_uint8(in_s, in_data); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x3 << 5) | in_count; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_data); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x60); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_data); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf3); \ + out_uint16_le(in_s, in_count); \ + out_uint8(in_s, in_data); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* color */ #define OUT_COLOR_COUNT2(in_count, in_s, in_data) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x3 << 5) | in_count; \ - out_uint8(in_s, temp); \ - out_uint16_le(in_s, in_data); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x60); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - out_uint16_le(in_s, in_data); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf3); \ - out_uint16_le(in_s, in_count); \ - out_uint16_le(in_s, in_data); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x3 << 5) | in_count; \ + out_uint8(in_s, temp); \ + out_uint16_le(in_s, in_data); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x60); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + out_uint16_le(in_s, in_data); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf3); \ + out_uint16_le(in_s, in_count); \ + out_uint16_le(in_s, in_data); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* color */ #define OUT_COLOR_COUNT3(in_count, in_s, in_data) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x3 << 5) | in_count; \ - out_uint8(in_s, temp); \ - out_uint8(in_s, in_data & 0xff); \ - out_uint8(in_s, (in_data >> 8) & 0xff); \ - out_uint8(in_s, (in_data >> 16) & 0xff); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x60); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - out_uint8(in_s, in_data & 0xff); \ - out_uint8(in_s, (in_data >> 8) & 0xff); \ - out_uint8(in_s, (in_data >> 16) & 0xff); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf3); \ - out_uint16_le(in_s, in_count); \ - out_uint8(in_s, in_data & 0xff); \ - out_uint8(in_s, (in_data >> 8) & 0xff); \ - out_uint8(in_s, (in_data >> 16) & 0xff); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x3 << 5) | in_count; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_data & 0xff); \ + out_uint8(in_s, (in_data >> 8) & 0xff); \ + out_uint8(in_s, (in_data >> 16) & 0xff); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x60); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_data & 0xff); \ + out_uint8(in_s, (in_data >> 8) & 0xff); \ + out_uint8(in_s, (in_data >> 16) & 0xff); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf3); \ + out_uint16_le(in_s, in_count); \ + out_uint8(in_s, in_data & 0xff); \ + out_uint8(in_s, (in_data >> 8) & 0xff); \ + out_uint8(in_s, (in_data >> 16) & 0xff); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* copy */ #define OUT_COPY_COUNT1(in_count, in_s, in_data) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x4 << 5) | in_count; \ - out_uint8(in_s, temp); \ - out_uint8a(in_s, in_data->data, in_count); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x80); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - out_uint8a(in_s, in_data->data, in_count); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf4); \ - out_uint16_le(in_s, in_count); \ - out_uint8a(in_s, in_data->data, in_count); \ - } \ - } \ - in_count = 0; \ - init_stream(in_data, 0); \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x4 << 5) | in_count; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_data->data, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x80); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_data->data, in_count); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf4); \ + out_uint16_le(in_s, in_count); \ + out_uint8a(in_s, in_data->data, in_count); \ + } \ + } \ + in_count = 0; \ + init_stream(in_data, 0); \ + } /*****************************************************************************/ /* copy */ #define OUT_COPY_COUNT2(in_count, in_s, in_data) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x4 << 5) | in_count; \ - out_uint8(in_s, temp); \ - temp = in_count * 2; \ - out_uint8a(in_s, in_data->data, temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x80); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - temp = in_count * 2; \ - out_uint8a(in_s, in_data->data, temp); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf4); \ - out_uint16_le(in_s, in_count); \ - temp = in_count * 2; \ - out_uint8a(in_s, in_data->data, temp); \ - } \ - } \ - in_count = 0; \ - init_stream(in_data, 0); \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x4 << 5) | in_count; \ + out_uint8(in_s, temp); \ + temp = in_count * 2; \ + out_uint8a(in_s, in_data->data, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x80); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + temp = in_count * 2; \ + out_uint8a(in_s, in_data->data, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf4); \ + out_uint16_le(in_s, in_count); \ + temp = in_count * 2; \ + out_uint8a(in_s, in_data->data, temp); \ + } \ + } \ + in_count = 0; \ + init_stream(in_data, 0); \ + } /*****************************************************************************/ /* copy */ #define OUT_COPY_COUNT3(in_count, in_s, in_data) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x4 << 5) | in_count; \ - out_uint8(in_s, temp); \ - temp = in_count * 3; \ - out_uint8a(in_s, in_data->end, temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x80); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - temp = in_count * 3; \ - out_uint8a(in_s, in_data->end, temp); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf4); \ - out_uint16_le(in_s, in_count); \ - temp = in_count * 3; \ - out_uint8a(in_s, in_data->end, temp); \ - } \ - } \ - in_count = 0; \ - init_stream(in_data, 0); \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x4 << 5) | in_count; \ + out_uint8(in_s, temp); \ + temp = in_count * 3; \ + out_uint8a(in_s, in_data->end, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x80); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + temp = in_count * 3; \ + out_uint8a(in_s, in_data->end, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf4); \ + out_uint16_le(in_s, in_count); \ + temp = in_count * 3; \ + out_uint8a(in_s, in_data->end, temp); \ + } \ + } \ + in_count = 0; \ + init_stream(in_data, 0); \ + } /*****************************************************************************/ /* bicolor */ #define OUT_BICOLOR_COUNT1(in_count, in_s, in_color1, in_color2) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count / 2 < 16) \ { \ - temp = (0xe << 4) | (in_count / 2); \ - out_uint8(in_s, temp); \ - out_uint8(in_s, in_color1); \ - out_uint8(in_s, in_color2); \ - } \ - else if (in_count / 2 < 256 + 16) \ - { \ - out_uint8(in_s, 0xe0); \ - temp = in_count / 2 - 16; \ - out_uint8(in_s, temp); \ - out_uint8(in_s, in_color1); \ - out_uint8(in_s, in_color2); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf8); \ - temp = in_count / 2; \ - out_uint16_le(in_s, temp); \ - out_uint8(in_s, in_color1); \ - out_uint8(in_s, in_color2); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count / 2 < 16) \ + { \ + temp = (0xe << 4) | (in_count / 2); \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_color1); \ + out_uint8(in_s, in_color2); \ + } \ + else if (in_count / 2 < 256 + 16) \ + { \ + out_uint8(in_s, 0xe0); \ + temp = in_count / 2 - 16; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_color1); \ + out_uint8(in_s, in_color2); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf8); \ + temp = in_count / 2; \ + out_uint16_le(in_s, temp); \ + out_uint8(in_s, in_color1); \ + out_uint8(in_s, in_color2); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* bicolor */ #define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count / 2 < 16) \ { \ - temp = (0xe << 4) | (in_count / 2); \ - out_uint8(in_s, temp); \ - out_uint16_le(in_s, in_color1); \ - out_uint16_le(in_s, in_color2); \ - } \ - else if (in_count / 2 < 256 + 16) \ - { \ - out_uint8(in_s, 0xe0); \ - temp = in_count / 2 - 16; \ - out_uint8(in_s, temp); \ - out_uint16_le(in_s, in_color1); \ - out_uint16_le(in_s, in_color2); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf8); \ - temp = in_count / 2; \ - out_uint16_le(in_s, temp); \ - out_uint16_le(in_s, in_color1); \ - out_uint16_le(in_s, in_color2); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count / 2 < 16) \ + { \ + temp = (0xe << 4) | (in_count / 2); \ + out_uint8(in_s, temp); \ + out_uint16_le(in_s, in_color1); \ + out_uint16_le(in_s, in_color2); \ + } \ + else if (in_count / 2 < 256 + 16) \ + { \ + out_uint8(in_s, 0xe0); \ + temp = in_count / 2 - 16; \ + out_uint8(in_s, temp); \ + out_uint16_le(in_s, in_color1); \ + out_uint16_le(in_s, in_color2); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf8); \ + temp = in_count / 2; \ + out_uint16_le(in_s, temp); \ + out_uint16_le(in_s, in_color1); \ + out_uint16_le(in_s, in_color2); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* bicolor */ #define OUT_BICOLOR_COUNT3(in_count, in_s, in_color1, in_color2) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count / 2 < 16) \ { \ - temp = (0xe << 4) | (in_count / 2); \ - out_uint8(in_s, temp); \ - out_uint8(in_s, in_color1 & 0xff); \ - out_uint8(in_s, (in_color1 >> 8) & 0xff); \ - out_uint8(in_s, (in_color1 >> 16) & 0xff); \ - out_uint8(in_s, in_color2 & 0xff); \ - out_uint8(in_s, (in_color2 >> 8) & 0xff); \ - out_uint8(in_s, (in_color2 >> 16) & 0xff); \ - } \ - else if (in_count / 2 < 256 + 16) \ - { \ - out_uint8(in_s, 0xe0); \ - temp = in_count / 2 - 16; \ - out_uint8(in_s, temp); \ - out_uint8(in_s, in_color1 & 0xff); \ - out_uint8(in_s, (in_color1 >> 8) & 0xff); \ - out_uint8(in_s, (in_color1 >> 16) & 0xff); \ - out_uint8(in_s, in_color2 & 0xff); \ - out_uint8(in_s, (in_color2 >> 8) & 0xff); \ - out_uint8(in_s, (in_color2 >> 16) & 0xff); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf8); \ - temp = in_count / 2; \ - out_uint16_le(in_s, temp); \ - out_uint8(in_s, in_color1 & 0xff); \ - out_uint8(in_s, (in_color1 >> 8) & 0xff); \ - out_uint8(in_s, (in_color1 >> 16) & 0xff); \ - out_uint8(in_s, in_color2 & 0xff); \ - out_uint8(in_s, (in_color2 >> 8) & 0xff); \ - out_uint8(in_s, (in_color2 >> 16) & 0xff); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count / 2 < 16) \ + { \ + temp = (0xe << 4) | (in_count / 2); \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_color1 & 0xff); \ + out_uint8(in_s, (in_color1 >> 8) & 0xff); \ + out_uint8(in_s, (in_color1 >> 16) & 0xff); \ + out_uint8(in_s, in_color2 & 0xff); \ + out_uint8(in_s, (in_color2 >> 8) & 0xff); \ + out_uint8(in_s, (in_color2 >> 16) & 0xff); \ + } \ + else if (in_count / 2 < 256 + 16) \ + { \ + out_uint8(in_s, 0xe0); \ + temp = in_count / 2 - 16; \ + out_uint8(in_s, temp); \ + out_uint8(in_s, in_color1 & 0xff); \ + out_uint8(in_s, (in_color1 >> 8) & 0xff); \ + out_uint8(in_s, (in_color1 >> 16) & 0xff); \ + out_uint8(in_s, in_color2 & 0xff); \ + out_uint8(in_s, (in_color2 >> 8) & 0xff); \ + out_uint8(in_s, (in_color2 >> 16) & 0xff); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf8); \ + temp = in_count / 2; \ + out_uint16_le(in_s, temp); \ + out_uint8(in_s, in_color1 & 0xff); \ + out_uint8(in_s, (in_color1 >> 8) & 0xff); \ + out_uint8(in_s, (in_color1 >> 16) & 0xff); \ + out_uint8(in_s, in_color2 & 0xff); \ + out_uint8(in_s, (in_color2 >> 8) & 0xff); \ + out_uint8(in_s, (in_color2 >> 16) & 0xff); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* fill */ #define OUT_FILL_COUNT1(in_count, in_s) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - out_uint8(in_s, in_count); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x0); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf0); \ - out_uint16_le(in_s, in_count); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + out_uint8(in_s, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x0); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf0); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* fill */ #define OUT_FILL_COUNT2(in_count, in_s) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - out_uint8(in_s, in_count); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x0); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf0); \ - out_uint16_le(in_s, in_count); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + out_uint8(in_s, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x0); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf0); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* fill */ #define OUT_FILL_COUNT3(in_count, in_s) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - out_uint8(in_s, in_count); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x0); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf0); \ - out_uint16_le(in_s, in_count); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + out_uint8(in_s, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x0); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf0); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* mix */ #define OUT_MIX_COUNT1(in_count, in_s) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x1 << 5) | in_count; \ - out_uint8(in_s, temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x20); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf1); \ - out_uint16_le(in_s, in_count); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x1 << 5) | in_count; \ + out_uint8(in_s, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x20); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf1); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* mix */ #define OUT_MIX_COUNT2(in_count, in_s) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x1 << 5) | in_count; \ - out_uint8(in_s, temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x20); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf1); \ - out_uint16_le(in_s, in_count); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x1 << 5) | in_count; \ + out_uint8(in_s, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x20); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf1); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* mix */ #define OUT_MIX_COUNT3(in_count, in_s) \ -{ \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ { \ - temp = (0x1 << 5) | in_count; \ - out_uint8(in_s, temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - out_uint8(in_s, 0x20); \ - temp = in_count - 32; \ - out_uint8(in_s, temp); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf1); \ - out_uint16_le(in_s, in_count); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x1 << 5) | in_count; \ + out_uint8(in_s, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + out_uint8(in_s, 0x20); \ + temp = in_count - 32; \ + out_uint8(in_s, temp); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf1); \ + out_uint16_le(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* fom */ #define OUT_FOM_COUNT1(in_count, in_s, in_mask, in_mask_len) \ -{ \ - if (in_count > 0) \ - { \ - if ((in_count % 8) == 0 && in_count < 249) \ { \ - temp = (0x2 << 5) | (in_count / 8); \ - out_uint8(in_s, temp); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - else if (in_count < 256) \ - { \ - out_uint8(in_s, 0x40); \ - temp = in_count - 1; \ - out_uint8(in_s, temp); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf2); \ - out_uint16_le(in_s, in_count); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if ((in_count % 8) == 0 && in_count < 249) \ + { \ + temp = (0x2 << 5) | (in_count / 8); \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else if (in_count < 256) \ + { \ + out_uint8(in_s, 0x40); \ + temp = in_count - 1; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf2); \ + out_uint16_le(in_s, in_count); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* fom */ #define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \ -{ \ - if (in_count > 0) \ - { \ - if ((in_count % 8) == 0 && in_count < 249) \ { \ - temp = (0x2 << 5) | (in_count / 8); \ - out_uint8(in_s, temp); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - else if (in_count < 256) \ - { \ - out_uint8(in_s, 0x40); \ - temp = in_count - 1; \ - out_uint8(in_s, temp); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf2); \ - out_uint16_le(in_s, in_count); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if ((in_count % 8) == 0 && in_count < 249) \ + { \ + temp = (0x2 << 5) | (in_count / 8); \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else if (in_count < 256) \ + { \ + out_uint8(in_s, 0x40); \ + temp = in_count - 1; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf2); \ + out_uint16_le(in_s, in_count); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ /* fill or mix (fom) */ #define OUT_FOM_COUNT3(in_count, in_s, in_mask, in_mask_len) \ -{ \ - if (in_count > 0) \ - { \ - if ((in_count % 8) == 0 && in_count < 249) \ { \ - temp = (0x2 << 5) | (in_count / 8); \ - out_uint8(in_s, temp); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - else if (in_count < 256) \ - { \ - out_uint8(in_s, 0x40); \ - temp = in_count - 1; \ - out_uint8(in_s, temp); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - else \ - { \ - out_uint8(in_s, 0xf2); \ - out_uint16_le(in_s, in_count); \ - out_uint8a(in_s, in_mask, in_mask_len); \ - } \ - } \ - in_count = 0; \ -} + if (in_count > 0) \ + { \ + if ((in_count % 8) == 0 && in_count < 249) \ + { \ + temp = (0x2 << 5) | (in_count / 8); \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else if (in_count < 256) \ + { \ + out_uint8(in_s, 0x40); \ + temp = in_count - 1; \ + out_uint8(in_s, temp); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + else \ + { \ + out_uint8(in_s, 0xf2); \ + out_uint16_le(in_s, in_count); \ + out_uint8a(in_s, in_mask, in_mask_len); \ + } \ + } \ + in_count = 0; \ + } /*****************************************************************************/ #define TEST_FILL \ -((last_line == 0 && pixel == 0) || \ - (last_line != 0 && pixel == ypixel)) + ((last_line == 0 && pixel == 0) || \ + (last_line != 0 && pixel == ypixel)) #define TEST_MIX \ -((last_line == 0 && pixel == mix) || \ - (last_line != 0 && pixel == (ypixel ^ mix))) + ((last_line == 0 && pixel == mix) || \ + (last_line != 0 && pixel == (ypixel ^ mix))) #define TEST_FOM (TEST_FILL || TEST_MIX) #define TEST_COLOR (pixel == last_pixel) #define TEST_BICOLOR \ -( \ - (pixel != last_pixel) && \ - ( \ - (!bicolor_spin && pixel == bicolor1 && last_pixel == bicolor2) || \ - (bicolor_spin && pixel == bicolor2 && last_pixel == bicolor1) \ - ) \ -) + ( \ + (pixel != last_pixel) && \ + ( \ + (!bicolor_spin && pixel == bicolor1 && last_pixel == bicolor2) || \ + (bicolor_spin && pixel == bicolor2 && last_pixel == bicolor1) \ + ) \ + ) #define RESET_COUNTS \ -{ \ - bicolor_count = 0; \ - fill_count = 0; \ - color_count = 0; \ - mix_count = 0; \ - fom_count = 0; \ - fom_mask_len = 0; \ - bicolor_spin = 0; \ -} + { \ + bicolor_count = 0; \ + fill_count = 0; \ + color_count = 0; \ + mix_count = 0; \ + fom_count = 0; \ + fom_mask_len = 0; \ + bicolor_spin = 0; \ + } /*****************************************************************************/ int APP_CC -xrdp_bitmap_compress(char* in_data, int width, int height, - struct stream* s, int bpp, int byte_limit, - int start_line, struct stream* temp_s, +xrdp_bitmap_compress(char *in_data, int width, int height, + struct stream *s, int bpp, int byte_limit, + int start_line, struct stream *temp_s, int e) { - char* line; - char* last_line; - char fom_mask[8192]; /* good for up to 64K bitmap */ - int lines_sent; - int pixel; - int count; - int color_count; - int last_pixel; - int bicolor_count; - int bicolor1; - int bicolor2; - int bicolor_spin; - int end; - int i; - int out_count; - int ypixel; - int last_ypixel; - int fill_count; - int mix_count; - int mix; - int fom_count; - int fom_mask_len; - int temp; /* used in macros */ + char *line; + char *last_line; + char fom_mask[8192]; /* good for up to 64K bitmap */ + int lines_sent; + int pixel; + int count; + int color_count; + int last_pixel; + int bicolor_count; + int bicolor1; + int bicolor2; + int bicolor_spin; + int end; + int i; + int out_count; + int ypixel; + int last_ypixel; + int fill_count; + int mix_count; + int mix; + int fom_count; + int fom_mask_len; + int temp; /* used in macros */ - init_stream(temp_s, 0); - fom_mask_len = 0; - last_line = 0; - lines_sent = 0; - end = width + e; - count = 0; - color_count = 0; - last_pixel = 0; - last_ypixel = 0; - bicolor_count = 0; - bicolor1 = 0; - bicolor2 = 0; - bicolor_spin = 0; - fill_count = 0; - mix_count = 0; - fom_count = 0; - if (bpp == 8) - { - mix = 0xff; - out_count = end; - line = in_data + width * start_line; - while (start_line >= 0 && out_count < 32768) + init_stream(temp_s, 0); + fom_mask_len = 0; + last_line = 0; + lines_sent = 0; + end = width + e; + count = 0; + color_count = 0; + last_pixel = 0; + last_ypixel = 0; + bicolor_count = 0; + bicolor1 = 0; + bicolor2 = 0; + bicolor_spin = 0; + fill_count = 0; + mix_count = 0; + fom_count = 0; + + if (bpp == 8) { - i = (s->p - s->data) + count; - if (i - color_count >= byte_limit && - i - bicolor_count >= byte_limit && - i - fill_count >= byte_limit && - i - mix_count >= byte_limit && - i - fom_count >= byte_limit) - { - break; - } - out_count += end; - for (i = 0; i < end; i++) - { - /* read next pixel */ - IN_PIXEL8(line, i, 0, width, last_pixel, pixel); - IN_PIXEL8(last_line, i, 0, width, last_ypixel, ypixel); - if (!TEST_FILL) + mix = 0xff; + out_count = end; + line = in_data + width * start_line; + + while (start_line >= 0 && out_count < 32768) + { + i = (s->p - s->data) + count; + + if (i - color_count >= byte_limit && + i - bicolor_count >= byte_limit && + i - fill_count >= byte_limit && + i - mix_count >= byte_limit && + i - fom_count >= byte_limit) + { + break; + } + + out_count += end; + + for (i = 0; i < end; i++) + { + /* read next pixel */ + IN_PIXEL8(line, i, 0, width, last_pixel, pixel); + IN_PIXEL8(last_line, i, 0, width, last_ypixel, ypixel); + + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FILL_COUNT1(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + } + + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_MIX_COUNT1(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + } + + if (!TEST_COLOR) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_COLOR_COUNT1(color_count, s, last_pixel); + RESET_COUNTS; + } + + color_count = 0; + } + + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); + } + + RESET_COUNTS; + } + + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = 0; + } + + if (!TEST_FOM) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + if (TEST_FILL) + { + fill_count++; + } + + if (TEST_MIX) + { + mix_count++; + } + + if (TEST_COLOR) + { + color_count++; + } + + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + + fom_count++; + } + + out_uint8(temp_s, pixel); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FILL_COUNT1(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_MIX_COUNT1(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + last_line = line; + line = line - width; + start_line--; + lines_sent++; + } + + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) { - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { count -= fill_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_FILL_COUNT1(fill_count, s); - RESET_COUNTS; - } - fill_count = 0; } - if (!TEST_MIX) + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) { - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { count -= mix_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_MIX_COUNT1(mix_count, s); - RESET_COUNTS; - } - mix_count = 0; } - if (!TEST_COLOR) + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) { - if (color_count > 3 && - color_count >= fill_count && - color_count >= bicolor_count && - color_count >= mix_count && - color_count >= fom_count) - { count -= color_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_COLOR_COUNT1(color_count, s, last_pixel); - RESET_COUNTS; - } - color_count = 0; } - if (!TEST_BICOLOR) + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) { - if (bicolor_count > 3 && - bicolor_count >= fill_count && - bicolor_count >= color_count && - bicolor_count >= mix_count && - bicolor_count >= fom_count) - { if ((bicolor_count % 2) == 0) { - count -= bicolor_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); } else { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); } - RESET_COUNTS; - } - bicolor_count = 0; - bicolor1 = last_pixel; - bicolor2 = pixel; - bicolor_spin = 0; + + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); } - if (!TEST_FOM) + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) { - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { count -= fom_count; OUT_COPY_COUNT1(count, s, temp_s); OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } - fom_count = 0; - fom_mask_len = 0; } - if (TEST_FILL) + else { - fill_count++; + OUT_COPY_COUNT1(count, s, temp_s); } - if (TEST_MIX) + } + else if ((bpp == 15) || (bpp == 16)) + { + mix = (bpp == 15) ? 0xba1f : 0xffff; + out_count = end * 2; + line = in_data + width * start_line * 2; + + while (start_line >= 0 && out_count < 32768) { - mix_count++; + i = (s->p - s->data) + count * 2; + + if (i - (color_count * 2) >= byte_limit && + i - (bicolor_count * 2) >= byte_limit && + i - (fill_count * 2) >= byte_limit && + i - (mix_count * 2) >= byte_limit && + i - (fom_count * 2) >= byte_limit) + { + break; + } + + out_count += end * 2; + + for (i = 0; i < end; i++) + { + /* read next pixel */ + IN_PIXEL16(line, i, 0, width, last_pixel, pixel); + IN_PIXEL16(last_line, i, 0, width, last_ypixel, ypixel); + + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + } + + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + } + + if (!TEST_COLOR) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_COLOR_COUNT2(color_count, s, last_pixel); + RESET_COUNTS; + } + + color_count = 0; + } + + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); + } + + RESET_COUNTS; + } + + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = 0; + } + + if (!TEST_FOM) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + if (TEST_FILL) + { + fill_count++; + } + + if (TEST_MIX) + { + mix_count++; + } + + if (TEST_COLOR) + { + color_count++; + } + + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + + fom_count++; + } + + out_uint16_le(temp_s, pixel); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + last_line = line; + line = line - width * 2; + start_line--; + lines_sent++; } - if (TEST_COLOR) - { - color_count++; - } - if (TEST_BICOLOR) - { - bicolor_spin = !bicolor_spin; - bicolor_count++; - } - if (TEST_FOM) - { - if ((fom_count % 8) == 0) - { - fom_mask[fom_mask_len] = 0; - fom_mask_len++; - } - if (pixel == (ypixel ^ mix)) - { - fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); - } - fom_count++; - } - out_uint8(temp_s, pixel); - count++; - last_pixel = pixel; - last_ypixel = ypixel; - } - /* can't take fix, mix, or fom past first line */ - if (last_line == 0) - { + if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) { - count -= fill_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_FILL_COUNT1(fill_count, s); - RESET_COUNTS; - } - fill_count = 0; - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_MIX_COUNT1(mix_count, s); - RESET_COUNTS; - } - mix_count = 0; - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } - fom_count = 0; - fom_mask_len = 0; - } - last_line = line; - line = line - width; - start_line--; - lines_sent++; - } - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { - count -= fill_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_FILL_COUNT1(fill_count, s); - } - else if (mix_count > 3 && - mix_count >= color_count && - mix_count >= bicolor_count && - mix_count >= fill_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_MIX_COUNT1(mix_count, s); - } - else if (color_count > 3 && - color_count >= mix_count && - color_count >= bicolor_count && - color_count >= fill_count && - color_count >= fom_count) - { - count -= color_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_COLOR_COUNT1(color_count, s, last_pixel); - } - else if (bicolor_count > 3 && - bicolor_count >= mix_count && - bicolor_count >= color_count && - bicolor_count >= fill_count && - bicolor_count >= fom_count) - { - if ((bicolor_count % 2) == 0) - { - count -= bicolor_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); - } - else - { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); - } - count -= bicolor_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); - } - else if (fom_count > 3 && - fom_count >= mix_count && - fom_count >= color_count && - fom_count >= fill_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT1(count, s, temp_s); - OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); - } - else - { - OUT_COPY_COUNT1(count, s, temp_s); - } - } - else if ((bpp == 15) || (bpp == 16)) - { - mix = (bpp == 15) ? 0xba1f : 0xffff; - out_count = end * 2; - line = in_data + width * start_line * 2; - while (start_line >= 0 && out_count < 32768) - { - i = (s->p - s->data) + count * 2; - if (i - (color_count * 2) >= byte_limit && - i - (bicolor_count * 2) >= byte_limit && - i - (fill_count * 2) >= byte_limit && - i - (mix_count * 2) >= byte_limit && - i - (fom_count * 2) >= byte_limit) - { - break; - } - out_count += end * 2; - for (i = 0; i < end; i++) - { - /* read next pixel */ - IN_PIXEL16(line, i, 0, width, last_pixel, pixel); - IN_PIXEL16(last_line, i, 0, width, last_ypixel, ypixel); - if (!TEST_FILL) - { - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { count -= fill_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_FILL_COUNT2(fill_count, s); - RESET_COUNTS; - } - fill_count = 0; } - if (!TEST_MIX) + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) { - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { count -= mix_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_MIX_COUNT2(mix_count, s); - RESET_COUNTS; - } - mix_count = 0; } - if (!TEST_COLOR) + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) { - if (color_count > 3 && - color_count >= fill_count && - color_count >= bicolor_count && - color_count >= mix_count && - color_count >= fom_count) - { count -= color_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_COLOR_COUNT2(color_count, s, last_pixel); - RESET_COUNTS; - } - color_count = 0; } - if (!TEST_BICOLOR) + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) { - if (bicolor_count > 3 && - bicolor_count >= fill_count && - bicolor_count >= color_count && - bicolor_count >= mix_count && - bicolor_count >= fom_count) - { if ((bicolor_count % 2) == 0) { - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); } else { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); } - RESET_COUNTS; - } - bicolor_count = 0; - bicolor1 = last_pixel; - bicolor2 = pixel; - bicolor_spin = 0; + + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); } - if (!TEST_FOM) + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) { - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { count -= fom_count; OUT_COPY_COUNT2(count, s, temp_s); OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } - fom_count = 0; - fom_mask_len = 0; } - if (TEST_FILL) + else { - fill_count++; + OUT_COPY_COUNT2(count, s, temp_s); } - if (TEST_MIX) + } + else if (bpp == 24) + { + mix = 0xffffff; + out_count = end * 3; + line = in_data + width * start_line * 4; + + while (start_line >= 0 && out_count < 32768) { - mix_count++; + i = (s->p - s->data) + count * 3; + + if (i - (color_count * 3) >= byte_limit && + i - (bicolor_count * 3) >= byte_limit && + i - (fill_count * 3) >= byte_limit && + i - (mix_count * 3) >= byte_limit && + i - (fom_count * 3) >= byte_limit) + { + break; + } + + out_count += end * 3; + + for (i = 0; i < end; i++) + { + /* read next pixel */ + IN_PIXEL32(line, i, 0, width, last_pixel, pixel); + IN_PIXEL32(last_line, i, 0, width, last_ypixel, ypixel); + + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FILL_COUNT3(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + } + + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_MIX_COUNT3(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + } + + if (!TEST_COLOR) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_COLOR_COUNT3(color_count, s, last_pixel); + RESET_COUNTS; + } + + color_count = 0; + } + + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); + } + + RESET_COUNTS; + } + + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = 0; + } + + if (!TEST_FOM) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + if (TEST_FILL) + { + fill_count++; + } + + if (TEST_MIX) + { + mix_count++; + } + + if (TEST_COLOR) + { + color_count++; + } + + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + + fom_count++; + } + + out_uint8(temp_s, pixel & 0xff); + out_uint8(temp_s, (pixel >> 8) & 0xff); + out_uint8(temp_s, (pixel >> 16) & 0xff); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FILL_COUNT3(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_MIX_COUNT3(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + last_line = line; + line = line - width * 4; + start_line--; + lines_sent++; } - if (TEST_COLOR) - { - color_count++; - } - if (TEST_BICOLOR) - { - bicolor_spin = !bicolor_spin; - bicolor_count++; - } - if (TEST_FOM) - { - if ((fom_count % 8) == 0) - { - fom_mask[fom_mask_len] = 0; - fom_mask_len++; - } - if (pixel == (ypixel ^ mix)) - { - fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); - } - fom_count++; - } - out_uint16_le(temp_s, pixel); - count++; - last_pixel = pixel; - last_ypixel = ypixel; - } - /* can't take fix, mix, or fom past first line */ - if (last_line == 0) - { + if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) { - count -= fill_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FILL_COUNT2(fill_count, s); - RESET_COUNTS; - } - fill_count = 0; - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_MIX_COUNT2(mix_count, s); - RESET_COUNTS; - } - mix_count = 0; - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } - fom_count = 0; - fom_mask_len = 0; - } - last_line = line; - line = line - width * 2; - start_line--; - lines_sent++; - } - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { - count -= fill_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FILL_COUNT2(fill_count, s); - } - else if (mix_count > 3 && - mix_count >= color_count && - mix_count >= bicolor_count && - mix_count >= fill_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_MIX_COUNT2(mix_count, s); - } - else if (color_count > 3 && - color_count >= mix_count && - color_count >= bicolor_count && - color_count >= fill_count && - color_count >= fom_count) - { - count -= color_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_COLOR_COUNT2(color_count, s, last_pixel); - } - else if (bicolor_count > 3 && - bicolor_count >= mix_count && - bicolor_count >= color_count && - bicolor_count >= fill_count && - bicolor_count >= fom_count) - { - if ((bicolor_count % 2) == 0) - { - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); - } - else - { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); - } - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); - } - else if (fom_count > 3 && - fom_count >= mix_count && - fom_count >= color_count && - fom_count >= fill_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); - } - else - { - OUT_COPY_COUNT2(count, s, temp_s); - } - } - else if (bpp == 24) - { - mix = 0xffffff; - out_count = end * 3; - line = in_data + width * start_line * 4; - while (start_line >= 0 && out_count < 32768) - { - i = (s->p - s->data) + count * 3; - if (i - (color_count * 3) >= byte_limit && - i - (bicolor_count * 3) >= byte_limit && - i - (fill_count * 3) >= byte_limit && - i - (mix_count * 3) >= byte_limit && - i - (fom_count * 3) >= byte_limit) - { - break; - } - out_count += end * 3; - for (i = 0; i < end; i++) - { - /* read next pixel */ - IN_PIXEL32(line, i, 0, width, last_pixel, pixel); - IN_PIXEL32(last_line, i, 0, width, last_ypixel, ypixel); - if (!TEST_FILL) - { - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { count -= fill_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FILL_COUNT3(fill_count, s); - RESET_COUNTS; - } - fill_count = 0; } - if (!TEST_MIX) + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) { - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { count -= mix_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_MIX_COUNT3(mix_count, s); - RESET_COUNTS; - } - mix_count = 0; } - if (!TEST_COLOR) + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) { - if (color_count > 3 && - color_count >= fill_count && - color_count >= bicolor_count && - color_count >= mix_count && - color_count >= fom_count) - { count -= color_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_COLOR_COUNT3(color_count, s, last_pixel); - RESET_COUNTS; - } - color_count = 0; } - if (!TEST_BICOLOR) + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) { - if (bicolor_count > 3 && - bicolor_count >= fill_count && - bicolor_count >= color_count && - bicolor_count >= mix_count && - bicolor_count >= fom_count) - { if ((bicolor_count % 2) == 0) { - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); } else { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); } - RESET_COUNTS; - } - bicolor_count = 0; - bicolor1 = last_pixel; - bicolor2 = pixel; - bicolor_spin = 0; + + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); } - if (!TEST_FOM) + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) { - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { count -= fom_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } - fom_count = 0; - fom_mask_len = 0; } - if (TEST_FILL) + else { - fill_count++; + OUT_COPY_COUNT3(count, s, temp_s); } - if (TEST_MIX) - { - mix_count++; - } - if (TEST_COLOR) - { - color_count++; - } - if (TEST_BICOLOR) - { - bicolor_spin = !bicolor_spin; - bicolor_count++; - } - if (TEST_FOM) - { - if ((fom_count % 8) == 0) - { - fom_mask[fom_mask_len] = 0; - fom_mask_len++; - } - if (pixel == (ypixel ^ mix)) - { - fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); - } - fom_count++; - } - out_uint8(temp_s, pixel & 0xff); - out_uint8(temp_s, (pixel >> 8) & 0xff); - out_uint8(temp_s, (pixel >> 16) & 0xff); - count++; - last_pixel = pixel; - last_ypixel = ypixel; - } - /* can't take fix, mix, or fom past first line */ - if (last_line == 0) - { - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { - count -= fill_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_FILL_COUNT3(fill_count, s); - RESET_COUNTS; - } - fill_count = 0; - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_MIX_COUNT3(mix_count, s); - RESET_COUNTS; - } - mix_count = 0; - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } - fom_count = 0; - fom_mask_len = 0; - } - last_line = line; - line = line - width * 4; - start_line--; - lines_sent++; } - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { - count -= fill_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_FILL_COUNT3(fill_count, s); - } - else if (mix_count > 3 && - mix_count >= color_count && - mix_count >= bicolor_count && - mix_count >= fill_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_MIX_COUNT3(mix_count, s); - } - else if (color_count > 3 && - color_count >= mix_count && - color_count >= bicolor_count && - color_count >= fill_count && - color_count >= fom_count) - { - count -= color_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_COLOR_COUNT3(color_count, s, last_pixel); - } - else if (bicolor_count > 3 && - bicolor_count >= mix_count && - bicolor_count >= color_count && - bicolor_count >= fill_count && - bicolor_count >= fom_count) - { - if ((bicolor_count % 2) == 0) - { - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); - } - else - { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); - } - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); - } - else if (fom_count > 3 && - fom_count >= mix_count && - fom_count >= color_count && - fom_count >= fill_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); - } - else - { - OUT_COPY_COUNT3(count, s, temp_s); - } - } - return lines_sent; + + return lines_sent; } diff --git a/libxrdp/xrdp_channel.c b/libxrdp/xrdp_channel.c index 2b3d23a5..6f40b751 100644 --- a/libxrdp/xrdp_channel.c +++ b/libxrdp/xrdp_channel.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2006-2010 - - channel layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2006-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * channel layer + */ #include "libxrdp.h" @@ -31,86 +29,96 @@ /*****************************************************************************/ /* returns pointer or nil on error */ -static struct mcs_channel_item* APP_CC -xrdp_channel_get_item(struct xrdp_channel* self, int channel_id) +static struct mcs_channel_item *APP_CC +xrdp_channel_get_item(struct xrdp_channel *self, int channel_id) { - struct mcs_channel_item* channel; - if(self->mcs_layer->channel_list==NULL) - { - g_writeln("xrdp_channel_get_item - No channel initialized"); - return NULL ; - } - channel = (struct mcs_channel_item*) - list_get_item(self->mcs_layer->channel_list, channel_id); - return channel; + struct mcs_channel_item *channel; + + if (self->mcs_layer->channel_list == NULL) + { + g_writeln("xrdp_channel_get_item - No channel initialized"); + return NULL ; + } + + channel = (struct mcs_channel_item *) + list_get_item(self->mcs_layer->channel_list, channel_id); + return channel; } /*****************************************************************************/ -struct xrdp_channel* APP_CC -xrdp_channel_create(struct xrdp_sec* owner, struct xrdp_mcs* mcs_layer) +struct xrdp_channel *APP_CC +xrdp_channel_create(struct xrdp_sec *owner, struct xrdp_mcs *mcs_layer) { - struct xrdp_channel* self; + struct xrdp_channel *self; - self = (struct xrdp_channel*)g_malloc(sizeof(struct xrdp_channel), 1); - self->sec_layer = owner; - self->mcs_layer = mcs_layer; - return self; + self = (struct xrdp_channel *)g_malloc(sizeof(struct xrdp_channel), 1); + self->sec_layer = owner; + self->mcs_layer = mcs_layer; + return self; } /*****************************************************************************/ /* returns error */ void APP_CC -xrdp_channel_delete(struct xrdp_channel* self) +xrdp_channel_delete(struct xrdp_channel *self) { - if (self == 0) - { - return; - } - g_memset(self,0,sizeof(struct xrdp_channel)); - g_free(self); + if (self == 0) + { + return; + } + + g_memset(self, 0, sizeof(struct xrdp_channel)); + g_free(self); } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_channel_init(struct xrdp_channel* self, struct stream* s) +xrdp_channel_init(struct xrdp_channel *self, struct stream *s) { - if (xrdp_sec_init(self->sec_layer, s) != 0) - { - return 1; - } - s_push_layer(s, channel_hdr, 8); - return 0; + if (xrdp_sec_init(self->sec_layer, s) != 0) + { + return 1; + } + + s_push_layer(s, channel_hdr, 8); + return 0; } /*****************************************************************************/ /* returns error */ /* This sends data out to the secure layer. */ int APP_CC -xrdp_channel_send(struct xrdp_channel* self, struct stream* s, int channel_id, +xrdp_channel_send(struct xrdp_channel *self, struct stream *s, int channel_id, int total_data_len, int flags) { - struct mcs_channel_item* channel; + struct mcs_channel_item *channel; - channel = xrdp_channel_get_item(self, channel_id); - if (channel == NULL) - { - g_writeln("xrdp_channel_send - no such channel"); - return 1; - } - s_pop_layer(s, channel_hdr); - out_uint32_le(s, total_data_len); - if (channel->flags & XR_CHANNEL_OPTION_SHOW_PROTOCOL) - { - flags |= CHANNEL_FLAG_SHOW_PROTOCOL; - } - out_uint32_le(s, flags); - if (xrdp_sec_send(self->sec_layer, s, channel->chanid) != 0) - { - g_writeln("xrdp_channel_send - failure sending data"); - return 1; - } - return 0; + channel = xrdp_channel_get_item(self, channel_id); + + if (channel == NULL) + { + g_writeln("xrdp_channel_send - no such channel"); + return 1; + } + + s_pop_layer(s, channel_hdr); + out_uint32_le(s, total_data_len); + + if (channel->flags & XR_CHANNEL_OPTION_SHOW_PROTOCOL) + { + flags |= CHANNEL_FLAG_SHOW_PROTOCOL; + } + + out_uint32_le(s, flags); + + if (xrdp_sec_send(self->sec_layer, s, channel->chanid) != 0) + { + g_writeln("xrdp_channel_send - failure sending data"); + return 1; + } + + return 0; } /*****************************************************************************/ @@ -118,36 +126,38 @@ xrdp_channel_send(struct xrdp_channel* self, struct stream* s, int channel_id, /* this will inform the callback, whatever it is that some channel data is ready. the default for this is a call to xrdp_wm.c. */ static int APP_CC -xrdp_channel_call_callback(struct xrdp_channel* self, struct stream* s, +xrdp_channel_call_callback(struct xrdp_channel *self, struct stream *s, int channel_id, int total_data_len, int flags) { - struct xrdp_session* session; - int rv; - int size; + struct xrdp_session *session; + int rv; + int size; - rv = 0; - session = self->sec_layer->rdp_layer->session; - if (session != 0) - { - if (session->callback != 0) + rv = 0; + session = self->sec_layer->rdp_layer->session; + + if (session != 0) { - size = (int)(s->end - s->p); - /* in xrdp_wm.c */ - rv = session->callback(session->id, 0x5555, - MAKELONG(channel_id, flags), - size, (tbus)(s->p), total_data_len); + if (session->callback != 0) + { + size = (int)(s->end - s->p); + /* in xrdp_wm.c */ + rv = session->callback(session->id, 0x5555, + MAKELONG(channel_id, flags), + size, (tbus)(s->p), total_data_len); + } + else + { + g_writeln("in xrdp_channel_call_callback, session->callback is nil"); + } } else { - g_writeln("in xrdp_channel_call_callback, session->callback is nil"); + g_writeln("in xrdp_channel_call_callback, session is nil"); } - } - else - { - g_writeln("in xrdp_channel_call_callback, session is nil"); - } - return rv; + + return rv; } /*****************************************************************************/ @@ -157,30 +167,32 @@ xrdp_channel_call_callback(struct xrdp_channel* self, struct stream* s, 'chanid' passed in here is the mcs channel id so it MCS_GLOBAL_CHANNEL plus something. */ int APP_CC -xrdp_channel_process(struct xrdp_channel* self, struct stream* s, +xrdp_channel_process(struct xrdp_channel *self, struct stream *s, int chanid) { - int length; - int flags; - int rv; - int channel_id; - struct mcs_channel_item* channel; + int length; + int flags; + int rv; + int channel_id; + struct mcs_channel_item *channel; - /* this assumes that the channels are in order of chanid(mcs channel id) - but they should be, see xrdp_sec_process_mcs_data_channels - the first channel should be MCS_GLOBAL_CHANNEL + 1, second - one should be MCS_GLOBAL_CHANNEL + 2, and so on */ - channel_id = (chanid - MCS_GLOBAL_CHANNEL) - 1; - channel = xrdp_channel_get_item(self, channel_id); - if (channel == NULL) - { - g_writeln("xrdp_channel_process, channel not found"); - return 1; - } - rv = 0; - in_uint32_le(s, length); - in_uint32_le(s, flags); - rv = xrdp_channel_call_callback(self, s, channel_id, length, flags); - return rv; + /* this assumes that the channels are in order of chanid(mcs channel id) + but they should be, see xrdp_sec_process_mcs_data_channels + the first channel should be MCS_GLOBAL_CHANNEL + 1, second + one should be MCS_GLOBAL_CHANNEL + 2, and so on */ + channel_id = (chanid - MCS_GLOBAL_CHANNEL) - 1; + channel = xrdp_channel_get_item(self, channel_id); + + if (channel == NULL) + { + g_writeln("xrdp_channel_process, channel not found"); + return 1; + } + + rv = 0; + in_uint32_le(s, length); + in_uint32_le(s, flags); + rv = xrdp_channel_call_callback(self, s, channel_id, length, flags); + return rv; } diff --git a/libxrdp/xrdp_fastpath.c b/libxrdp/xrdp_fastpath.c index 9a147b1b..35d90407 100644 --- a/libxrdp/xrdp_fastpath.c +++ b/libxrdp/xrdp_fastpath.c @@ -20,177 +20,190 @@ #include "libxrdp.h" /*****************************************************************************/ -struct xrdp_fastpath* APP_CC -xrdp_fastpath_create(struct xrdp_session* session) +struct xrdp_fastpath *APP_CC +xrdp_fastpath_create(struct xrdp_session *session) { - struct xrdp_fastpath* self; + struct xrdp_fastpath *self; - self = (struct xrdp_fastpath*)g_malloc(sizeof(struct xrdp_fastpath), 1); - self->tcp_layer = - ((struct xrdp_rdp*)session->rdp)->sec_layer-> - mcs_layer->iso_layer->tcp_layer; - make_stream(self->out_s); - init_stream(self->out_s, FASTPATH_MAX_PACKET_SIZE); - return self; + self = (struct xrdp_fastpath *)g_malloc(sizeof(struct xrdp_fastpath), 1); + self->tcp_layer = + ((struct xrdp_rdp *)session->rdp)->sec_layer-> + mcs_layer->iso_layer->tcp_layer; + make_stream(self->out_s); + init_stream(self->out_s, FASTPATH_MAX_PACKET_SIZE); + return self; } /*****************************************************************************/ void APP_CC -xrdp_fastpath_delete(struct xrdp_fastpath* self) +xrdp_fastpath_delete(struct xrdp_fastpath *self) { - if (self == 0) - { - return; - } - free_stream(self->out_s); - g_free(self); + if (self == 0) + { + return; + } + + free_stream(self->out_s); + g_free(self); } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_fastpath_reset(struct xrdp_fastpath* self) +xrdp_fastpath_reset(struct xrdp_fastpath *self) { - return 0; + return 0; } int APP_CC -xrdp_fastpath_init(struct xrdp_fastpath* self) +xrdp_fastpath_init(struct xrdp_fastpath *self) { - return 0; + return 0; } /*****************************************************************************/ int APP_CC -xrdp_fastpath_send_update_pdu(struct xrdp_fastpath* self, tui8 updateCode, - struct stream* s) +xrdp_fastpath_send_update_pdu(struct xrdp_fastpath *self, tui8 updateCode, + struct stream *s) { - tui16 len; - tui16 maxLen; - tui32 payloadLeft; - tui8 fragment; - struct stream* s_send; - int compression; - int i; - int i32; + tui16 len; + tui16 maxLen; + tui32 payloadLeft; + tui8 fragment; + struct stream *s_send; + int compression; + int i; + int i32; - compression = 0; - s_send = self->out_s; - maxLen = FASTPATH_MAX_PACKET_SIZE - 6; /* 6 bytes for header */ - payloadLeft = (s->end - s->data); - for (i = 0; payloadLeft > 0; i++) - { - if (payloadLeft > maxLen) + compression = 0; + s_send = self->out_s; + maxLen = FASTPATH_MAX_PACKET_SIZE - 6; /* 6 bytes for header */ + payloadLeft = (s->end - s->data); + + for (i = 0; payloadLeft > 0; i++) { - len = maxLen; + if (payloadLeft > maxLen) + { + len = maxLen; + } + else + { + len = payloadLeft; + } + + payloadLeft -= len; + + if (payloadLeft == 0) + { + fragment = i ? FASTPATH_FRAGMENT_LAST : FASTPATH_FRAGMENT_SINGLE; + } + else + { + fragment = i ? FASTPATH_FRAGMENT_NEXT : FASTPATH_FRAGMENT_FIRST; + } + + init_stream(s_send, 0); + out_uint8(s_send, 0); /* fOutputHeader */ + i32 = ((len + 6) >> 8) | 0x80; + out_uint8(s_send, i32); /* use 2 bytes for length even length < 128 ??? */ + i32 = (len + 6) & 0xff; + out_uint8(s_send, i32); + i32 = (updateCode & 0x0f) | ((fragment & 0x03) << 4) | + ((compression & 0x03) << 6); + out_uint8(s_send, i32); + out_uint16_le(s_send, len); + s_copy(s_send, s, len); + s_mark_end(s_send); + + if (xrdp_tcp_send(self->tcp_layer, s_send) != 0) + { + return 1; + } } - else - { - len = payloadLeft; - } - payloadLeft -= len; - if (payloadLeft == 0) - { - fragment = i ? FASTPATH_FRAGMENT_LAST : FASTPATH_FRAGMENT_SINGLE; - } - else - { - fragment = i ? FASTPATH_FRAGMENT_NEXT : FASTPATH_FRAGMENT_FIRST; - } - init_stream(s_send, 0); - out_uint8(s_send, 0); /* fOutputHeader */ - i32 = ((len + 6) >> 8) | 0x80; - out_uint8(s_send, i32); /* use 2 bytes for length even length < 128 ??? */ - i32 = (len + 6) & 0xff; - out_uint8(s_send, i32); - i32 = (updateCode & 0x0f) | ((fragment & 0x03) << 4) | - ((compression & 0x03) << 6); - out_uint8(s_send, i32); - out_uint16_le(s_send, len); - s_copy(s_send, s, len); - s_mark_end(s_send); - if (xrdp_tcp_send(self->tcp_layer, s_send) != 0) - { - return 1; - } - } - return 0; + + return 0; } /*****************************************************************************/ int -xrdp_fastpath_process_update(struct xrdp_fastpath* self, tui8 updateCode, - tui32 size, struct stream* s) +xrdp_fastpath_process_update(struct xrdp_fastpath *self, tui8 updateCode, + tui32 size, struct stream *s) { - switch (updateCode) - { - case FASTPATH_UPDATETYPE_ORDERS: - case FASTPATH_UPDATETYPE_BITMAP: - case FASTPATH_UPDATETYPE_PALETTE: - case FASTPATH_UPDATETYPE_SYNCHRONIZE: - case FASTPATH_UPDATETYPE_SURFCMDS: - case FASTPATH_UPDATETYPE_PTR_NULL: - case FASTPATH_UPDATETYPE_PTR_DEFAULT: - case FASTPATH_UPDATETYPE_PTR_POSITION: - case FASTPATH_UPDATETYPE_COLOR: - case FASTPATH_UPDATETYPE_CACHED: - case FASTPATH_UPDATETYPE_POINTER: - break; - default: - g_writeln("xrdp_fastpath_process_update: unknown updateCode 0x%X", - updateCode); - break; - } + switch (updateCode) + { + case FASTPATH_UPDATETYPE_ORDERS: + case FASTPATH_UPDATETYPE_BITMAP: + case FASTPATH_UPDATETYPE_PALETTE: + case FASTPATH_UPDATETYPE_SYNCHRONIZE: + case FASTPATH_UPDATETYPE_SURFCMDS: + case FASTPATH_UPDATETYPE_PTR_NULL: + case FASTPATH_UPDATETYPE_PTR_DEFAULT: + case FASTPATH_UPDATETYPE_PTR_POSITION: + case FASTPATH_UPDATETYPE_COLOR: + case FASTPATH_UPDATETYPE_CACHED: + case FASTPATH_UPDATETYPE_POINTER: + break; + default: + g_writeln("xrdp_fastpath_process_update: unknown updateCode 0x%X", + updateCode); + break; + } - return 0; + return 0; } /*****************************************************************************/ int APP_CC -xrdp_fastpath_process_data(struct xrdp_fastpath* self, struct stream* s, +xrdp_fastpath_process_data(struct xrdp_fastpath *self, struct stream *s, tui8 header) { - tui8 encryptionFlags; - tui8 numberEvents; - tui8 length2; - tui8 updateHeader; - tui8 updateCode; - tui8 updateFrag; - tui8 updateComp; - tui16 length; - tui32 size; + tui8 encryptionFlags; + tui8 numberEvents; + tui8 length2; + tui8 updateHeader; + tui8 updateCode; + tui8 updateFrag; + tui8 updateComp; + tui16 length; + tui32 size; - encryptionFlags = (header & 0xc0) >> 6; - numberEvents = (header & 0x3c) >> 2; - xrdp_tcp_recv(self->tcp_layer, s, 1); - in_uint8(s, length); - if (length & 0x80) - { + encryptionFlags = (header & 0xc0) >> 6; + numberEvents = (header & 0x3c) >> 2; xrdp_tcp_recv(self->tcp_layer, s, 1); - in_uint8(s, length2); - length = (length & 0x7f) << 8 + length2 - 3; - } - else - { - length -= 2; - } - xrdp_tcp_recv(self->tcp_layer, s, length); - if (encryptionFlags != 0) - { - /* TODO decryption ...*/ - } - /* parse updateHeader */ - in_uint8(s, updateHeader); - updateCode = (updateHeader & 0x0f); - updateFrag = (updateHeader & 0x30) >> 4; - updateComp = (updateHeader & 0xc0) >> 6; - if (updateFrag && updateComp) - { - /* TODO */ - g_writeln("xrdp_fastpath_process_data: updateFrag=%d, updateComp=%d", - updateFrag,updateComp); - return 1; - } - in_uint16_le(s, size); - return xrdp_fastpath_process_update(self, updateCode, size, s); + in_uint8(s, length); + + if (length & 0x80) + { + xrdp_tcp_recv(self->tcp_layer, s, 1); + in_uint8(s, length2); + length = (length & 0x7f) << 8 + length2 - 3; + } + else + { + length -= 2; + } + + xrdp_tcp_recv(self->tcp_layer, s, length); + + if (encryptionFlags != 0) + { + /* TODO decryption ...*/ + } + + /* parse updateHeader */ + in_uint8(s, updateHeader); + updateCode = (updateHeader & 0x0f); + updateFrag = (updateHeader & 0x30) >> 4; + updateComp = (updateHeader & 0xc0) >> 6; + + if (updateFrag && updateComp) + { + /* TODO */ + g_writeln("xrdp_fastpath_process_data: updateFrag=%d, updateComp=%d", + updateFrag, updateComp); + return 1; + } + + in_uint16_le(s, size); + return xrdp_fastpath_process_update(self, updateCode, size, s); } diff --git a/libxrdp/xrdp_iso.c b/libxrdp/xrdp_iso.c index 7fee92e6..8dedc131 100644 --- a/libxrdp/xrdp_iso.c +++ b/libxrdp/xrdp_iso.c @@ -1,197 +1,216 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - iso layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * iso layer + */ #include "libxrdp.h" /*****************************************************************************/ -struct xrdp_iso* APP_CC -xrdp_iso_create(struct xrdp_mcs* owner, struct trans* trans) +struct xrdp_iso *APP_CC +xrdp_iso_create(struct xrdp_mcs *owner, struct trans *trans) { - struct xrdp_iso* self; + struct xrdp_iso *self; - DEBUG((" in xrdp_iso_create")); - self = (struct xrdp_iso*)g_malloc(sizeof(struct xrdp_iso), 1); - self->mcs_layer = owner; - self->tcp_layer = xrdp_tcp_create(self, trans); - DEBUG((" out xrdp_iso_create")); - return self; + DEBUG((" in xrdp_iso_create")); + self = (struct xrdp_iso *)g_malloc(sizeof(struct xrdp_iso), 1); + self->mcs_layer = owner; + self->tcp_layer = xrdp_tcp_create(self, trans); + DEBUG((" out xrdp_iso_create")); + return self; } /*****************************************************************************/ void APP_CC -xrdp_iso_delete(struct xrdp_iso* self) +xrdp_iso_delete(struct xrdp_iso *self) { - if (self == 0) - { - return; - } - xrdp_tcp_delete(self->tcp_layer); - g_free(self); + if (self == 0) + { + return; + } + + xrdp_tcp_delete(self->tcp_layer); + g_free(self); } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_iso_recv_msg(struct xrdp_iso* self, struct stream* s, int* code) +xrdp_iso_recv_msg(struct xrdp_iso *self, struct stream *s, int *code) { - int ver; - int len; + int ver; + int len; + + *code = 0; + + if (xrdp_tcp_recv(self->tcp_layer, s, 4) != 0) + { + return 1; + } + + in_uint8(s, ver); + + if (ver != 3) + { + return 1; + } - *code = 0; - if (xrdp_tcp_recv(self->tcp_layer, s, 4) != 0) - { - return 1; - } - in_uint8(s, ver); - if (ver != 3) - { - return 1; - } - in_uint8s(s, 1); - in_uint16_be(s, len); - if (xrdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) - { - return 1; - } - in_uint8s(s, 1); - in_uint8(s, *code); - if (*code == ISO_PDU_DT) - { in_uint8s(s, 1); - } - else - { - in_uint8s(s, 5); - } - return 0; + in_uint16_be(s, len); + + if (xrdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) + { + return 1; + } + + in_uint8s(s, 1); + in_uint8(s, *code); + + if (*code == ISO_PDU_DT) + { + in_uint8s(s, 1); + } + else + { + in_uint8s(s, 5); + } + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_iso_recv(struct xrdp_iso* self, struct stream* s) +xrdp_iso_recv(struct xrdp_iso *self, struct stream *s) { - int code; + int code; - DEBUG((" in xrdp_iso_recv")); - if (xrdp_iso_recv_msg(self, s, &code) != 0) - { - DEBUG((" out xrdp_iso_recv xrdp_iso_recv_msg return non zero")); - return 1; - } - if (code != ISO_PDU_DT) - { - DEBUG((" out xrdp_iso_recv code != ISO_PDU_DT")); - return 1; - } - DEBUG((" out xrdp_iso_recv")); - return 0; + DEBUG((" in xrdp_iso_recv")); + + if (xrdp_iso_recv_msg(self, s, &code) != 0) + { + DEBUG((" out xrdp_iso_recv xrdp_iso_recv_msg return non zero")); + return 1; + } + + if (code != ISO_PDU_DT) + { + DEBUG((" out xrdp_iso_recv code != ISO_PDU_DT")); + return 1; + } + + DEBUG((" out xrdp_iso_recv")); + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_iso_send_msg(struct xrdp_iso* self, struct stream* s, int code) +xrdp_iso_send_msg(struct xrdp_iso *self, struct stream *s, int code) { - if (xrdp_tcp_init(self->tcp_layer, s) != 0) - { - return 1; - } - out_uint8(s, 3); - out_uint8(s, 0); - out_uint16_be(s, 11); /* length */ - out_uint8(s, 6); - out_uint8(s, code); - out_uint16_le(s, 0); - out_uint16_le(s, 0); - out_uint8(s, 0); - s_mark_end(s); - if (xrdp_tcp_send(self->tcp_layer, s) != 0) - { - return 1; - } - return 0; + if (xrdp_tcp_init(self->tcp_layer, s) != 0) + { + return 1; + } + + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, 11); /* length */ + out_uint8(s, 6); + out_uint8(s, code); + out_uint16_le(s, 0); + out_uint16_le(s, 0); + out_uint8(s, 0); + s_mark_end(s); + + if (xrdp_tcp_send(self->tcp_layer, s) != 0) + { + return 1; + } + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_iso_incoming(struct xrdp_iso* self) +xrdp_iso_incoming(struct xrdp_iso *self) { - int code; - struct stream* s; + int code; + struct stream *s; - make_stream(s); - init_stream(s, 8192); - DEBUG((" in xrdp_iso_incoming")); - if (xrdp_iso_recv_msg(self, s, &code) != 0) - { + make_stream(s); + init_stream(s, 8192); + DEBUG((" in xrdp_iso_incoming")); + + if (xrdp_iso_recv_msg(self, s, &code) != 0) + { + free_stream(s); + return 1; + } + + if (code != ISO_PDU_CR) + { + free_stream(s); + return 1; + } + + if (xrdp_iso_send_msg(self, s, ISO_PDU_CC) != 0) + { + free_stream(s); + return 1; + } + + DEBUG((" out xrdp_iso_incoming")); free_stream(s); - return 1; - } - if (code != ISO_PDU_CR) - { - free_stream(s); - return 1; - } - if (xrdp_iso_send_msg(self, s, ISO_PDU_CC) != 0) - { - free_stream(s); - return 1; - } - DEBUG((" out xrdp_iso_incoming")); - free_stream(s); - return 0; + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_iso_init(struct xrdp_iso* self, struct stream* s) +xrdp_iso_init(struct xrdp_iso *self, struct stream *s) { - xrdp_tcp_init(self->tcp_layer, s); - s_push_layer(s, iso_hdr, 7); - return 0; + xrdp_tcp_init(self->tcp_layer, s); + s_push_layer(s, iso_hdr, 7); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_iso_send(struct xrdp_iso* self, struct stream* s) +xrdp_iso_send(struct xrdp_iso *self, struct stream *s) { - int len; + int len; - DEBUG((" in xrdp_iso_send")); - s_pop_layer(s, iso_hdr); - len = s->end - s->p; - out_uint8(s, 3); - out_uint8(s, 0); - out_uint16_be(s, len); - out_uint8(s, 2); - out_uint8(s, ISO_PDU_DT); - out_uint8(s, 0x80); - if (xrdp_tcp_send(self->tcp_layer, s) != 0) - { - return 1; - } - DEBUG((" out xrdp_iso_send")); - return 0; + DEBUG((" in xrdp_iso_send")); + s_pop_layer(s, iso_hdr); + len = s->end - s->p; + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, len); + out_uint8(s, 2); + out_uint8(s, ISO_PDU_DT); + out_uint8(s, 0x80); + + if (xrdp_tcp_send(self->tcp_layer, s) != 0) + { + return 1; + } + + DEBUG((" out xrdp_iso_send")); + return 0; } diff --git a/libxrdp/xrdp_jpeg_compress.c b/libxrdp/xrdp_jpeg_compress.c index 8561982f..f8681e2b 100644 --- a/libxrdp/xrdp_jpeg_compress.c +++ b/libxrdp/xrdp_jpeg_compress.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2012 - - jpeg compressor - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * jpeg compressor + */ #include "libxrdp.h" @@ -33,10 +31,10 @@ struct mydata_comp { - char* cb; - int cb_bytes; - int total_done; - int overwrite; + char *cb; + int cb_bytes; + int total_done; + int overwrite; }; /*****************************************************************************/ @@ -44,13 +42,13 @@ struct mydata_comp static void DEFAULT_CC my_init_destination(j_compress_ptr cinfo) { - struct mydata_comp* md; + struct mydata_comp *md; - md = (struct mydata_comp*)(cinfo->client_data); - md->total_done = 0; - md->overwrite = 0; - cinfo->dest->next_output_byte = md->cb; - cinfo->dest->free_in_buffer = md->cb_bytes; + md = (struct mydata_comp *)(cinfo->client_data); + md->total_done = 0; + md->overwrite = 0; + cinfo->dest->next_output_byte = md->cb; + cinfo->dest->free_in_buffer = md->cb_bytes; } /*****************************************************************************/ @@ -58,16 +56,16 @@ my_init_destination(j_compress_ptr cinfo) static int DEFAULT_CC my_empty_output_buffer(j_compress_ptr cinfo) { - struct mydata_comp* md; - int chunk_bytes; + struct mydata_comp *md; + int chunk_bytes; - md = (struct mydata_comp*)(cinfo->client_data); - chunk_bytes = md->cb_bytes; - md->total_done += chunk_bytes; - cinfo->dest->next_output_byte = md->cb; - cinfo->dest->free_in_buffer = md->cb_bytes; - md->overwrite = 1; - return 1; + md = (struct mydata_comp *)(cinfo->client_data); + chunk_bytes = md->cb_bytes; + md->total_done += chunk_bytes; + cinfo->dest->next_output_byte = md->cb; + cinfo->dest->free_in_buffer = md->cb_bytes; + md->overwrite = 1; + return 1; } /*****************************************************************************/ @@ -75,149 +73,158 @@ my_empty_output_buffer(j_compress_ptr cinfo) static void DEFAULT_CC my_term_destination(j_compress_ptr cinfo) { - struct mydata_comp* md; - int chunk_bytes; + struct mydata_comp *md; + int chunk_bytes; - md = (struct mydata_comp*)(cinfo->client_data); - chunk_bytes = md->cb_bytes - cinfo->dest->free_in_buffer; - md->total_done += chunk_bytes; + md = (struct mydata_comp *)(cinfo->client_data); + chunk_bytes = md->cb_bytes - cinfo->dest->free_in_buffer; + md->total_done += chunk_bytes; } /*****************************************************************************/ static int APP_CC -jp_do_compress(char* data, int width, int height, int bpp, int quality, - char* comp_data, int* comp_data_bytes) +jp_do_compress(char *data, int width, int height, int bpp, int quality, + char *comp_data, int *comp_data_bytes) { - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - struct jpeg_destination_mgr dst_mgr; - struct mydata_comp md; - JSAMPROW row_pointer[4]; - int Bpp; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + struct jpeg_destination_mgr dst_mgr; + struct mydata_comp md; + JSAMPROW row_pointer[4]; + int Bpp; - Bpp = (bpp + 7) / 8; - memset(&cinfo, 0, sizeof(cinfo)); - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - memset(&md, 0, sizeof(md)); - md.cb = comp_data, - md.cb_bytes = *comp_data_bytes; - cinfo.client_data = &md; - memset(&dst_mgr, 0, sizeof(dst_mgr)); - dst_mgr.init_destination = my_init_destination; - dst_mgr.empty_output_buffer = my_empty_output_buffer; - dst_mgr.term_destination = my_term_destination; - cinfo.dest = &dst_mgr; - cinfo.image_width = width; - cinfo.image_height = height; - cinfo.input_components = Bpp; - cinfo.in_color_space = JCS_RGB; - jpeg_set_defaults(&cinfo); - cinfo.num_components = 3; - cinfo.dct_method = JDCT_FLOAT; - jpeg_set_quality(&cinfo, quality, 1); - jpeg_start_compress(&cinfo, 1); - while (cinfo.next_scanline + 3 < cinfo.image_height) - { - row_pointer[0] = data; - data += width * Bpp; - row_pointer[1] = data; - data += width * Bpp; - row_pointer[2] = data; - data += width * Bpp; - row_pointer[3] = data; - data += width * Bpp; - jpeg_write_scanlines(&cinfo, row_pointer, 4); - } - while (cinfo.next_scanline < cinfo.image_height) - { - row_pointer[0] = data; - data += width * Bpp; - jpeg_write_scanlines(&cinfo, row_pointer, 1); - } - jpeg_finish_compress(&cinfo); - *comp_data_bytes = md.total_done; - jpeg_destroy_compress(&cinfo); - if (md.overwrite) - { - return 1; - } - return 0; + Bpp = (bpp + 7) / 8; + memset(&cinfo, 0, sizeof(cinfo)); + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + memset(&md, 0, sizeof(md)); + md.cb = comp_data, + md.cb_bytes = *comp_data_bytes; + cinfo.client_data = &md; + memset(&dst_mgr, 0, sizeof(dst_mgr)); + dst_mgr.init_destination = my_init_destination; + dst_mgr.empty_output_buffer = my_empty_output_buffer; + dst_mgr.term_destination = my_term_destination; + cinfo.dest = &dst_mgr; + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = Bpp; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + cinfo.num_components = 3; + cinfo.dct_method = JDCT_FLOAT; + jpeg_set_quality(&cinfo, quality, 1); + jpeg_start_compress(&cinfo, 1); + + while (cinfo.next_scanline + 3 < cinfo.image_height) + { + row_pointer[0] = data; + data += width * Bpp; + row_pointer[1] = data; + data += width * Bpp; + row_pointer[2] = data; + data += width * Bpp; + row_pointer[3] = data; + data += width * Bpp; + jpeg_write_scanlines(&cinfo, row_pointer, 4); + } + + while (cinfo.next_scanline < cinfo.image_height) + { + row_pointer[0] = data; + data += width * Bpp; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + jpeg_finish_compress(&cinfo); + *comp_data_bytes = md.total_done; + jpeg_destroy_compress(&cinfo); + + if (md.overwrite) + { + return 1; + } + + return 0; } /*****************************************************************************/ static int APP_CC -jpeg_compress(char* in_data, int width, int height, - struct stream* s, struct stream* temp_s, int bpp, +jpeg_compress(char *in_data, int width, int height, + struct stream *s, struct stream *temp_s, int bpp, int byte_limit, int e, int quality) { - char* data; - tui32* src32; - tui16* src16; - tui8* dst8; - tui32 pixel; - int red; - int blue; - int green; - int j; - int i; - int cdata_bytes; + char *data; + tui32 *src32; + tui16 *src16; + tui8 *dst8; + tui32 pixel; + int red; + int blue; + int green; + int j; + int i; + int cdata_bytes; - data = temp_s->data; - dst8 = data; - if (bpp == 24) - { - src32 = (tui32*)in_data; - for (j = 0; j < height; j++) + data = temp_s->data; + dst8 = data; + + if (bpp == 24) { - for (i = 0; i < width; i++) - { - pixel = src32[i + j * width]; - SPLITCOLOR32(red, green, blue, pixel); - *(dst8++)= blue; - *(dst8++)= green; - *(dst8++)= red; - } - for (i = 0; i < e; i++) - { - *(dst8++) = blue; - *(dst8++) = green; - *(dst8++) = red; - } + src32 = (tui32 *)in_data; + + for (j = 0; j < height; j++) + { + for (i = 0; i < width; i++) + { + pixel = src32[i + j * width]; + SPLITCOLOR32(red, green, blue, pixel); + *(dst8++) = blue; + *(dst8++) = green; + *(dst8++) = red; + } + + for (i = 0; i < e; i++) + { + *(dst8++) = blue; + *(dst8++) = green; + *(dst8++) = red; + } + } } - } - else - { - g_writeln("bpp wrong %d", bpp); - } - cdata_bytes = byte_limit; - jp_do_compress(data, width + e, height, 24, quality, s->p, &cdata_bytes); - s->p += cdata_bytes; - return cdata_bytes; + else + { + g_writeln("bpp wrong %d", bpp); + } + + cdata_bytes = byte_limit; + jp_do_compress(data, width + e, height, 24, quality, s->p, &cdata_bytes); + s->p += cdata_bytes; + return cdata_bytes; } /*****************************************************************************/ int APP_CC -xrdp_jpeg_compress(char* in_data, int width, int height, - struct stream* s, int bpp, int byte_limit, - int start_line, struct stream* temp_s, +xrdp_jpeg_compress(char *in_data, int width, int height, + struct stream *s, int bpp, int byte_limit, + int start_line, struct stream *temp_s, int e, int quality) { - jpeg_compress(in_data, width, height, s, temp_s, bpp, byte_limit, - e, quality); - return height; + jpeg_compress(in_data, width, height, s, temp_s, bpp, byte_limit, + e, quality); + return height; } #else /*****************************************************************************/ int APP_CC -xrdp_jpeg_compress(char* in_data, int width, int height, - struct stream* s, int bpp, int byte_limit, - int start_line, struct stream* temp_s, +xrdp_jpeg_compress(char *in_data, int width, int height, + struct stream *s, int bpp, int byte_limit, + int start_line, struct stream *temp_s, int e, int quality) { - return height; + return height; } #endif diff --git a/libxrdp/xrdp_mcs.c b/libxrdp/xrdp_mcs.c index 618a3433..a2793960 100644 --- a/libxrdp/xrdp_mcs.c +++ b/libxrdp/xrdp_mcs.c @@ -1,642 +1,721 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - mcs layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * mcs layer + */ #include "libxrdp.h" /*****************************************************************************/ -struct xrdp_mcs* APP_CC -xrdp_mcs_create(struct xrdp_sec* owner, struct trans* trans, - struct stream* client_mcs_data, - struct stream* server_mcs_data) +struct xrdp_mcs *APP_CC +xrdp_mcs_create(struct xrdp_sec *owner, struct trans *trans, + struct stream *client_mcs_data, + struct stream *server_mcs_data) { - struct xrdp_mcs* self; + struct xrdp_mcs *self; - DEBUG((" in xrdp_mcs_create")); - self = (struct xrdp_mcs*)g_malloc(sizeof(struct xrdp_mcs), 1); - self->sec_layer = owner; - self->userid = 1; - self->chanid = 1001; - self->client_mcs_data = client_mcs_data; - self->server_mcs_data = server_mcs_data; - self->iso_layer = xrdp_iso_create(self, trans); - self->channel_list = list_create(); - DEBUG((" out xrdp_mcs_create")); - return self; + DEBUG((" in xrdp_mcs_create")); + self = (struct xrdp_mcs *)g_malloc(sizeof(struct xrdp_mcs), 1); + self->sec_layer = owner; + self->userid = 1; + self->chanid = 1001; + self->client_mcs_data = client_mcs_data; + self->server_mcs_data = server_mcs_data; + self->iso_layer = xrdp_iso_create(self, trans); + self->channel_list = list_create(); + DEBUG((" out xrdp_mcs_create")); + return self; } /*****************************************************************************/ void APP_CC -xrdp_mcs_delete(struct xrdp_mcs* self) +xrdp_mcs_delete(struct xrdp_mcs *self) { - struct mcs_channel_item* channel_item; - int index; - int count; + struct mcs_channel_item *channel_item; + int index; + int count; - if (self == 0) - { - return; - } - /* here we have to free the channel items and anything in them */ - count = self->channel_list->count; - for (index = count - 1; index >= 0; index--) - { - channel_item = (struct mcs_channel_item*) - list_get_item(self->channel_list, index); - g_free(channel_item); - } - list_delete(self->channel_list); - xrdp_iso_delete(self->iso_layer); - /* make sure we get null pointer exception if struct is used again. */ - DEBUG(("xrdp_mcs_delete processed")) - g_memset(self,0,sizeof(struct xrdp_mcs)) ; - g_free(self); + if (self == 0) + { + return; + } + + /* here we have to free the channel items and anything in them */ + count = self->channel_list->count; + + for (index = count - 1; index >= 0; index--) + { + channel_item = (struct mcs_channel_item *) + list_get_item(self->channel_list, index); + g_free(channel_item); + } + + list_delete(self->channel_list); + xrdp_iso_delete(self->iso_layer); + /* make sure we get null pointer exception if struct is used again. */ + DEBUG(("xrdp_mcs_delete processed")) + g_memset(self, 0, sizeof(struct xrdp_mcs)) ; + g_free(self); } /*****************************************************************************/ /* This function sends channel join confirm*/ /* returns error = 1 ok = 0*/ static int APP_CC -xrdp_mcs_send_cjcf(struct xrdp_mcs* self, int userid, int chanid) +xrdp_mcs_send_cjcf(struct xrdp_mcs *self, int userid, int chanid) { - struct stream* s; + struct stream *s; + + DEBUG((" in xrdp_mcs_send_cjcf")); + make_stream(s); + init_stream(s, 8192); + + if (xrdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + DEBUG((" out xrdp_mcs_send_cjcf error")); + return 1; + } + + out_uint8(s, (MCS_CJCF << 2) | 2); + out_uint8(s, 0); + out_uint16_be(s, userid); + out_uint16_be(s, chanid); /* TODO Explain why we send this two times */ + out_uint16_be(s, chanid); + s_mark_end(s); + + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + DEBUG((" out xrdp_mcs_send_cjcf error")); + return 1; + } - DEBUG((" in xrdp_mcs_send_cjcf")); - make_stream(s); - init_stream(s, 8192); - if (xrdp_iso_init(self->iso_layer, s) != 0) - { free_stream(s); - DEBUG((" out xrdp_mcs_send_cjcf error")); - return 1; - } - out_uint8(s, (MCS_CJCF << 2) | 2); - out_uint8(s, 0); - out_uint16_be(s, userid); - out_uint16_be(s, chanid); /* TODO Explain why we send this two times */ - out_uint16_be(s, chanid); - s_mark_end(s); - if (xrdp_iso_send(self->iso_layer, s) != 0) - { - free_stream(s); - DEBUG((" out xrdp_mcs_send_cjcf error")); - return 1; - } - free_stream(s); - DEBUG((" out xrdp_mcs_send_cjcf")); - return 0; + DEBUG((" out xrdp_mcs_send_cjcf")); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_mcs_recv(struct xrdp_mcs* self, struct stream* s, int* chan) +xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) { - int appid; - int opcode; - int len; - int userid; - int chanid; + int appid; + int opcode; + int len; + int userid; + int chanid; - DEBUG((" in xrdp_mcs_recv")); - while (1) - { - if (xrdp_iso_recv(self->iso_layer, s) != 0) + DEBUG((" in xrdp_mcs_recv")); + + while (1) { - DEBUG((" out xrdp_mcs_recv xrdp_iso_recv returned non zero")); - return 1; + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + DEBUG((" out xrdp_mcs_recv xrdp_iso_recv returned non zero")); + return 1; + } + + in_uint8(s, opcode); + appid = opcode >> 2; + + if (appid == MCS_DPUM) /* Disconnect Provider Ultimatum */ + { + g_writeln("received Disconnect Provider Ultimatum"); + DEBUG((" out xrdp_mcs_recv appid != MCS_DPUM")); + return 1; + } + + /* this is channels getting added from the client */ + if (appid == MCS_CJRQ) + { + g_writeln("channel join request received"); + in_uint16_be(s, userid); + in_uint16_be(s, chanid); + DEBUG(("xrdp_mcs_recv adding channel %4.4x", chanid)); + + if (xrdp_mcs_send_cjcf(self, userid, chanid) != 0) + { + g_writeln("Non handled error from xrdp_mcs_send_cjcf") ; + } + + continue; + } + + if (appid == MCS_SDRQ || appid == MCS_SDIN) + { + break ; + } + else + { + g_writeln("Recieved an unhandled appid:%d", appid); + } + + break; } - in_uint8(s, opcode); - appid = opcode >> 2; - if (appid == MCS_DPUM) /* Disconnect Provider Ultimatum */ + + if (appid != MCS_SDRQ) { - g_writeln("received Disconnect Provider Ultimatum"); - DEBUG((" out xrdp_mcs_recv appid != MCS_DPUM")); - return 1; + DEBUG((" out xrdp_mcs_recv err got 0x%x need MCS_SDRQ", appid)); + return 1; } - /* this is channels getting added from the client */ - if (appid == MCS_CJRQ) + + in_uint8s(s, 2); + in_uint16_be(s, *chan); + in_uint8s(s, 1); + in_uint8(s, len); + + if (len & 0x80) { - g_writeln("channel join request received"); - in_uint16_be(s, userid); - in_uint16_be(s, chanid); - DEBUG(("xrdp_mcs_recv adding channel %4.4x", chanid)); - if(xrdp_mcs_send_cjcf(self, userid, chanid)!=0) - { - g_writeln("Non handled error from xrdp_mcs_send_cjcf") ; - } - continue; + in_uint8s(s, 1); } - if(appid==MCS_SDRQ || appid==MCS_SDIN) + + DEBUG((" out xrdp_mcs_recv")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, + int tag_val, int *len) +{ + int tag; + int l; + int i; + + if (tag_val > 0xff) { - break ; + in_uint16_be(s, tag); } else { - g_writeln("Recieved an unhandled appid:%d",appid); + in_uint8(s, tag); } - break; - } - if (appid != MCS_SDRQ) - { - DEBUG((" out xrdp_mcs_recv err got 0x%x need MCS_SDRQ", appid)); - return 1; - } - in_uint8s(s, 2); - in_uint16_be(s, *chan); - in_uint8s(s, 1); - in_uint8(s, len); - if (len & 0x80) - { - in_uint8s(s, 1); - } - DEBUG((" out xrdp_mcs_recv")); - return 0; -} -/*****************************************************************************/ -/* returns error */ -static int APP_CC -xrdp_mcs_ber_parse_header(struct xrdp_mcs* self, struct stream* s, - int tag_val, int* len) -{ - int tag; - int l; - int i; - - if (tag_val > 0xff) - { - in_uint16_be(s, tag); - } - else - { - in_uint8(s, tag); - } - if (tag != tag_val) - { - return 1; - } - in_uint8(s, l); - if (l & 0x80) - { - l = l & ~0x80; - *len = 0; - while (l > 0) + if (tag != tag_val) { - in_uint8(s, i); - *len = (*len << 8) | i; - l--; + return 1; + } + + in_uint8(s, l); + + if (l & 0x80) + { + l = l & ~0x80; + *len = 0; + + while (l > 0) + { + in_uint8(s, i); + *len = (*len << 8) | i; + l--; + } + } + else + { + *len = l; + } + + if (s_check(s)) + { + return 0; + } + else + { + return 1; } - } - else - { - *len = l; - } - if (s_check(s)) - { - return 0; - } - else - { - return 1; - } } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_parse_domain_params(struct xrdp_mcs* self, struct stream* s) +xrdp_mcs_parse_domain_params(struct xrdp_mcs *self, struct stream *s) { - int len; + int len; - if (xrdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0) - { - return 1; - } - in_uint8s(s, len); - if (s_check(s)) - { - return 0; - } - else - { - return 1; - } + if (xrdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0) + { + return 1; + } + + in_uint8s(s, len); + + if (s_check(s)) + { + return 0; + } + else + { + return 1; + } } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_recv_connect_initial(struct xrdp_mcs* self) +xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) { - int len; - struct stream* s; + int len; + struct stream *s; - make_stream(s); - init_stream(s, 8192); - if (xrdp_iso_recv(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - if (xrdp_mcs_ber_parse_header(self, s, MCS_CONNECT_INITIAL, &len) != 0) - { - free_stream(s); - return 1; - } - if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) - { - free_stream(s); - return 1; - } - in_uint8s(s, len); - if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) - { - free_stream(s); - return 1; - } - in_uint8s(s, len); - if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_BOOLEAN, &len) != 0) - { - free_stream(s); - return 1; - } - in_uint8s(s, len); - if (xrdp_mcs_parse_domain_params(self, s) != 0) - { - free_stream(s); - return 1; - } - if (xrdp_mcs_parse_domain_params(self, s) != 0) - { - free_stream(s); - return 1; - } - if (xrdp_mcs_parse_domain_params(self, s) != 0) - { - free_stream(s); - return 1; - } - if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) - { - free_stream(s); - return 1; - } - /* make a copy of client mcs data */ - init_stream(self->client_mcs_data, len); - out_uint8a(self->client_mcs_data, s->p, len); - in_uint8s(s, len); - s_mark_end(self->client_mcs_data); - if (s_check_end(s)) - { - free_stream(s); - return 0; - } - else - { - free_stream(s); - return 1; - } + make_stream(s); + init_stream(s, 8192); + + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + if (xrdp_mcs_ber_parse_header(self, s, MCS_CONNECT_INITIAL, &len) != 0) + { + free_stream(s); + return 1; + } + + if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) + { + free_stream(s); + return 1; + } + + in_uint8s(s, len); + + if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) + { + free_stream(s); + return 1; + } + + in_uint8s(s, len); + + if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_BOOLEAN, &len) != 0) + { + free_stream(s); + return 1; + } + + in_uint8s(s, len); + + if (xrdp_mcs_parse_domain_params(self, s) != 0) + { + free_stream(s); + return 1; + } + + if (xrdp_mcs_parse_domain_params(self, s) != 0) + { + free_stream(s); + return 1; + } + + if (xrdp_mcs_parse_domain_params(self, s) != 0) + { + free_stream(s); + return 1; + } + + if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) + { + free_stream(s); + return 1; + } + + /* make a copy of client mcs data */ + init_stream(self->client_mcs_data, len); + out_uint8a(self->client_mcs_data, s->p, len); + in_uint8s(s, len); + s_mark_end(self->client_mcs_data); + + if (s_check_end(s)) + { + free_stream(s); + return 0; + } + else + { + free_stream(s); + return 1; + } } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_recv_edrq(struct xrdp_mcs* self) +xrdp_mcs_recv_edrq(struct xrdp_mcs *self) { - int opcode; - struct stream* s; + int opcode; + struct stream *s; - make_stream(s); - init_stream(s, 8192); - if (xrdp_iso_recv(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - in_uint8(s, opcode); - if ((opcode >> 2) != MCS_EDRQ) - { - free_stream(s); - return 1; - } - in_uint8s(s, 2); - in_uint8s(s, 2); - if (opcode & 2) - { - in_uint16_be(s, self->userid); - } - if (!(s_check_end(s))) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} + make_stream(s); + init_stream(s, 8192); -/*****************************************************************************/ -/* returns error */ -static int APP_CC -xrdp_mcs_recv_aurq(struct xrdp_mcs* self) -{ - int opcode; - struct stream* s; + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } - make_stream(s); - init_stream(s, 8192); - if (xrdp_iso_recv(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - in_uint8(s, opcode); - if ((opcode >> 2) != MCS_AURQ) - { - free_stream(s); - return 1; - } - if (opcode & 2) - { - in_uint16_be(s, self->userid); - } - if (!(s_check_end(s))) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} + in_uint8(s, opcode); -/*****************************************************************************/ -/* returns error */ -static int APP_CC -xrdp_mcs_send_aucf(struct xrdp_mcs* self) -{ - struct stream* s; + if ((opcode >> 2) != MCS_EDRQ) + { + free_stream(s); + return 1; + } - DEBUG((" in xrdp_mcs_send_aucf")); - make_stream(s); - init_stream(s, 8192); - if (xrdp_iso_init(self->iso_layer, s) != 0) - { - free_stream(s); - DEBUG((" out xrdp_mcs_send_aucf error")); - return 1; - } - out_uint8(s, ((MCS_AUCF << 2) | 2)); - out_uint8s(s, 1); - out_uint16_be(s, self->userid); - s_mark_end(s); - if (xrdp_iso_send(self->iso_layer, s) != 0) - { - free_stream(s); - DEBUG((" out xrdp_mcs_send_aucf error")); - return 1; - } - free_stream(s); - DEBUG((" out xrdp_mcs_send_aucf")); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -xrdp_mcs_recv_cjrq(struct xrdp_mcs* self) -{ - int opcode; - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (xrdp_iso_recv(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - in_uint8(s, opcode); - if ((opcode >> 2) != MCS_CJRQ) - { - free_stream(s); - return 1; - } - in_uint8s(s, 4); - if (opcode & 2) - { in_uint8s(s, 2); - } - if (!(s_check_end(s))) - { + in_uint8s(s, 2); + + if (opcode & 2) + { + in_uint16_be(s, self->userid); + } + + if (!(s_check_end(s))) + { + free_stream(s); + return 1; + } + free_stream(s); - return 1; - } - free_stream(s); - return 0; + return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_ber_out_header(struct xrdp_mcs* self, struct stream* s, +xrdp_mcs_recv_aurq(struct xrdp_mcs *self) +{ + int opcode; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + in_uint8(s, opcode); + + if ((opcode >> 2) != MCS_AURQ) + { + free_stream(s); + return 1; + } + + if (opcode & 2) + { + in_uint16_be(s, self->userid); + } + + if (!(s_check_end(s))) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_send_aucf(struct xrdp_mcs *self) +{ + struct stream *s; + + DEBUG((" in xrdp_mcs_send_aucf")); + make_stream(s); + init_stream(s, 8192); + + if (xrdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + DEBUG((" out xrdp_mcs_send_aucf error")); + return 1; + } + + out_uint8(s, ((MCS_AUCF << 2) | 2)); + out_uint8s(s, 1); + out_uint16_be(s, self->userid); + s_mark_end(s); + + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + DEBUG((" out xrdp_mcs_send_aucf error")); + return 1; + } + + free_stream(s); + DEBUG((" out xrdp_mcs_send_aucf")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_recv_cjrq(struct xrdp_mcs *self) +{ + int opcode; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + in_uint8(s, opcode); + + if ((opcode >> 2) != MCS_CJRQ) + { + free_stream(s); + return 1; + } + + in_uint8s(s, 4); + + if (opcode & 2) + { + in_uint8s(s, 2); + } + + if (!(s_check_end(s))) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_mcs_ber_out_header(struct xrdp_mcs *self, struct stream *s, int tag_val, int len) { - if (tag_val > 0xff) - { - out_uint16_be(s, tag_val); - } - else - { - out_uint8(s, tag_val); - } - if (len >= 0x80) - { - out_uint8(s, 0x82); - out_uint16_be(s, len); - } - else - { - out_uint8(s, len); - } - return 0; + if (tag_val > 0xff) + { + out_uint16_be(s, tag_val); + } + else + { + out_uint8(s, tag_val); + } + + if (len >= 0x80) + { + out_uint8(s, 0x82); + out_uint16_be(s, len); + } + else + { + out_uint8(s, len); + } + + return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_ber_out_int8(struct xrdp_mcs* self, struct stream* s, int value) +xrdp_mcs_ber_out_int8(struct xrdp_mcs *self, struct stream *s, int value) { - xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); - out_uint8(s, value); - return 0; + xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); + out_uint8(s, value); + return 0; } #if 0 /* not used */ /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_ber_out_int16(struct xrdp_mcs* self, struct stream* s, int value) +xrdp_mcs_ber_out_int16(struct xrdp_mcs *self, struct stream *s, int value) { - xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 2); - out_uint8(s, (value >> 8)); - out_uint8(s, value); - return 0; + xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 2); + out_uint8(s, (value >> 8)); + out_uint8(s, value); + return 0; } #endif /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_ber_out_int24(struct xrdp_mcs* self, struct stream* s, int value) +xrdp_mcs_ber_out_int24(struct xrdp_mcs *self, struct stream *s, int value) { - xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 3); - out_uint8(s, (value >> 16)); - out_uint8(s, (value >> 8)); - out_uint8(s, value); - return 0; + xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 3); + out_uint8(s, (value >> 16)); + out_uint8(s, (value >> 8)); + out_uint8(s, value); + return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_out_domain_params(struct xrdp_mcs* self, struct stream* s, +xrdp_mcs_out_domain_params(struct xrdp_mcs *self, struct stream *s, int max_channels, int max_users, int max_tokens, int max_pdu_size) { - xrdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 26); - xrdp_mcs_ber_out_int8(self, s, max_channels); - xrdp_mcs_ber_out_int8(self, s, max_users); - xrdp_mcs_ber_out_int8(self, s, max_tokens); - xrdp_mcs_ber_out_int8(self, s, 1); - xrdp_mcs_ber_out_int8(self, s, 0); - xrdp_mcs_ber_out_int8(self, s, 1); - xrdp_mcs_ber_out_int24(self, s, max_pdu_size); - xrdp_mcs_ber_out_int8(self, s, 2); - return 0; + xrdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 26); + xrdp_mcs_ber_out_int8(self, s, max_channels); + xrdp_mcs_ber_out_int8(self, s, max_users); + xrdp_mcs_ber_out_int8(self, s, max_tokens); + xrdp_mcs_ber_out_int8(self, s, 1); + xrdp_mcs_ber_out_int8(self, s, 0); + xrdp_mcs_ber_out_int8(self, s, 1); + xrdp_mcs_ber_out_int24(self, s, max_pdu_size); + xrdp_mcs_ber_out_int8(self, s, 2); + return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mcs_send_connect_response(struct xrdp_mcs* self) +xrdp_mcs_send_connect_response(struct xrdp_mcs *self) { - int data_len; - struct stream* s; + int data_len; + struct stream *s; + + DEBUG((" in xrdp_mcs_send_connect_response")); + make_stream(s); + init_stream(s, 8192); + data_len = self->server_mcs_data->end - self->server_mcs_data->data; + xrdp_iso_init(self->iso_layer, s); + xrdp_mcs_ber_out_header(self, s, MCS_CONNECT_RESPONSE, data_len + 38); + xrdp_mcs_ber_out_header(self, s, BER_TAG_RESULT, 1); + out_uint8(s, 0); + xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); + out_uint8(s, 0); + xrdp_mcs_out_domain_params(self, s, 22, 3, 0, 0xfff8); + xrdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len); + /* mcs data */ + out_uint8a(s, self->server_mcs_data->data, data_len); + s_mark_end(s); + + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + DEBUG((" out xrdp_mcs_send_connect_response error")); + return 1; + } - DEBUG((" in xrdp_mcs_send_connect_response")); - make_stream(s); - init_stream(s, 8192); - data_len = self->server_mcs_data->end - self->server_mcs_data->data; - xrdp_iso_init(self->iso_layer, s); - xrdp_mcs_ber_out_header(self, s, MCS_CONNECT_RESPONSE, data_len + 38); - xrdp_mcs_ber_out_header(self, s, BER_TAG_RESULT, 1); - out_uint8(s, 0); - xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); - out_uint8(s, 0); - xrdp_mcs_out_domain_params(self, s, 22, 3, 0, 0xfff8); - xrdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len); - /* mcs data */ - out_uint8a(s, self->server_mcs_data->data, data_len); - s_mark_end(s); - if (xrdp_iso_send(self->iso_layer, s) != 0) - { free_stream(s); - DEBUG((" out xrdp_mcs_send_connect_response error")); - return 1; - } - free_stream(s); - DEBUG((" out xrdp_mcs_send_connect_response")); - return 0; + DEBUG((" out xrdp_mcs_send_connect_response")); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_mcs_incoming(struct xrdp_mcs* self) +xrdp_mcs_incoming(struct xrdp_mcs *self) { - DEBUG((" in xrdp_mcs_incoming")); - if (xrdp_iso_incoming(self->iso_layer) != 0) - { - return 1; - } - if (xrdp_mcs_recv_connect_initial(self) != 0) - { - return 1; - } - /* in xrdp_sec.c */ - if (xrdp_sec_process_mcs_data(self->sec_layer) != 0) - { - return 1; - } - /* in xrdp_sec.c */ - if (xrdp_sec_out_mcs_data(self->sec_layer) != 0) - { - return 1; - } - if (xrdp_mcs_send_connect_response(self) != 0) - { - return 1; - } - if (xrdp_mcs_recv_edrq(self) != 0) - { - return 1; - } - if (xrdp_mcs_recv_aurq(self) != 0) - { - return 1; - } - if (xrdp_mcs_send_aucf(self) != 0) - { - return 1; - } - if (xrdp_mcs_recv_cjrq(self) != 0) - { - return 1; - } - if (xrdp_mcs_send_cjcf(self, self->userid, - self->userid + MCS_USERCHANNEL_BASE) != 0) - { - return 1; - } - if (xrdp_mcs_recv_cjrq(self) != 0) - { - return 1; - } - if (xrdp_mcs_send_cjcf(self, self->userid, MCS_GLOBAL_CHANNEL) != 0) - { - return 1; - } - DEBUG((" out xrdp_mcs_incoming")); - return 0; + DEBUG((" in xrdp_mcs_incoming")); + + if (xrdp_iso_incoming(self->iso_layer) != 0) + { + return 1; + } + + if (xrdp_mcs_recv_connect_initial(self) != 0) + { + return 1; + } + + /* in xrdp_sec.c */ + if (xrdp_sec_process_mcs_data(self->sec_layer) != 0) + { + return 1; + } + + /* in xrdp_sec.c */ + if (xrdp_sec_out_mcs_data(self->sec_layer) != 0) + { + return 1; + } + + if (xrdp_mcs_send_connect_response(self) != 0) + { + return 1; + } + + if (xrdp_mcs_recv_edrq(self) != 0) + { + return 1; + } + + if (xrdp_mcs_recv_aurq(self) != 0) + { + return 1; + } + + if (xrdp_mcs_send_aucf(self) != 0) + { + return 1; + } + + if (xrdp_mcs_recv_cjrq(self) != 0) + { + return 1; + } + + if (xrdp_mcs_send_cjcf(self, self->userid, + self->userid + MCS_USERCHANNEL_BASE) != 0) + { + return 1; + } + + if (xrdp_mcs_recv_cjrq(self) != 0) + { + return 1; + } + + if (xrdp_mcs_send_cjcf(self, self->userid, MCS_GLOBAL_CHANNEL) != 0) + { + return 1; + } + + DEBUG((" out xrdp_mcs_incoming")); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_mcs_init(struct xrdp_mcs* self, struct stream* s) +xrdp_mcs_init(struct xrdp_mcs *self, struct stream *s) { - xrdp_iso_init(self->iso_layer, s); - s_push_layer(s, mcs_hdr, 8); - return 0; + xrdp_iso_init(self->iso_layer, s); + s_push_layer(s, mcs_hdr, 8); + return 0; } /*****************************************************************************/ @@ -644,118 +723,132 @@ xrdp_mcs_init(struct xrdp_mcs* self, struct stream* s) /* Inform the callback that an mcs packet has been sent. This is needed so the module can send any high priority mcs packets like audio. */ static int APP_CC -xrdp_mcs_call_callback(struct xrdp_mcs* self) +xrdp_mcs_call_callback(struct xrdp_mcs *self) { - int rv; - struct xrdp_session* session; + int rv; + struct xrdp_session *session; - rv = 0; - /* if there is a callback, call it here */ - session = self->sec_layer->rdp_layer->session; - if (session != 0) - { - if (session->callback != 0) + rv = 0; + /* if there is a callback, call it here */ + session = self->sec_layer->rdp_layer->session; + + if (session != 0) { - /* in xrdp_wm.c */ - rv = session->callback(session->id, 0x5556, 0, 0, 0, 0); + if (session->callback != 0) + { + /* in xrdp_wm.c */ + rv = session->callback(session->id, 0x5556, 0, 0, 0, 0); + } + else + { + g_writeln("in xrdp_mcs_send, session->callback is nil"); + } } else { - g_writeln("in xrdp_mcs_send, session->callback is nil"); + g_writeln("in xrdp_mcs_send, session is nil"); } - } - else - { - g_writeln("in xrdp_mcs_send, session is nil"); - } - return rv; + + return rv; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_mcs_send(struct xrdp_mcs* self, struct stream* s, int chan) +xrdp_mcs_send(struct xrdp_mcs *self, struct stream *s, int chan) { - int len; - char* lp; - //static int max_len = 0; + int len; + char *lp; + //static int max_len = 0; - DEBUG((" in xrdp_mcs_send")); - s_pop_layer(s, mcs_hdr); - len = (s->end - s->p) - 8; - if (len > 8192 * 2) - { - g_writeln("error in xrdp_mcs_send, size too bog, its %d", len); - } - //if (len > max_len) - //{ - // max_len = len; - // g_printf("mcs max length is %d\r\n", max_len); - //} - //g_printf("mcs length %d max length is %d\r\n", len, max_len); - //g_printf("mcs length %d\r\n", len); - out_uint8(s, MCS_SDIN << 2); - out_uint16_be(s, self->userid); - out_uint16_be(s, chan); - out_uint8(s, 0x70); - if (len >= 128) - { - len = len | 0x8000; - out_uint16_be(s, len); - } - else - { - out_uint8(s, len); - /* move everything up one byte */ - lp = s->p; - while (lp < s->end) + DEBUG((" in xrdp_mcs_send")); + s_pop_layer(s, mcs_hdr); + len = (s->end - s->p) - 8; + + if (len > 8192 * 2) { - lp[0] = lp[1]; - lp++; + g_writeln("error in xrdp_mcs_send, size too bog, its %d", len); } - s->end--; - } - if (xrdp_iso_send(self->iso_layer, s) != 0) - { - DEBUG((" out xrdp_mcs_send error")); - return 1; - } - /* todo, do we need to call this for every mcs packet, - maybe every 5 or so */ - if (chan == MCS_GLOBAL_CHANNEL) - { - xrdp_mcs_call_callback(self); - } - DEBUG((" out xrdp_mcs_send")); - return 0; + + //if (len > max_len) + //{ + // max_len = len; + // g_printf("mcs max length is %d\r\n", max_len); + //} + //g_printf("mcs length %d max length is %d\r\n", len, max_len); + //g_printf("mcs length %d\r\n", len); + out_uint8(s, MCS_SDIN << 2); + out_uint16_be(s, self->userid); + out_uint16_be(s, chan); + out_uint8(s, 0x70); + + if (len >= 128) + { + len = len | 0x8000; + out_uint16_be(s, len); + } + else + { + out_uint8(s, len); + /* move everything up one byte */ + lp = s->p; + + while (lp < s->end) + { + lp[0] = lp[1]; + lp++; + } + + s->end--; + } + + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + DEBUG((" out xrdp_mcs_send error")); + return 1; + } + + /* todo, do we need to call this for every mcs packet, + maybe every 5 or so */ + if (chan == MCS_GLOBAL_CHANNEL) + { + xrdp_mcs_call_callback(self); + } + + DEBUG((" out xrdp_mcs_send")); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_mcs_disconnect(struct xrdp_mcs* self) +xrdp_mcs_disconnect(struct xrdp_mcs *self) { - struct stream* s; + struct stream *s; + + DEBUG((" in xrdp_mcs_disconnect")); + make_stream(s); + init_stream(s, 8192); + + if (xrdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + DEBUG((" out xrdp_mcs_disconnect error")); + return 1; + } + + out_uint8(s, (MCS_DPUM << 2) | 1); + out_uint8(s, 0x80); + s_mark_end(s); + + if (xrdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + DEBUG((" out xrdp_mcs_disconnect error")); + return 1; + } - DEBUG((" in xrdp_mcs_disconnect")); - make_stream(s); - init_stream(s, 8192); - if (xrdp_iso_init(self->iso_layer, s) != 0) - { free_stream(s); - DEBUG((" out xrdp_mcs_disconnect error")); - return 1; - } - out_uint8(s, (MCS_DPUM << 2) | 1); - out_uint8(s, 0x80); - s_mark_end(s); - if (xrdp_iso_send(self->iso_layer, s) != 0) - { - free_stream(s); - DEBUG((" out xrdp_mcs_disconnect error")); - return 1; - } - free_stream(s); - DEBUG((" out xrdp_mcs_disconnect")); - return 0; + DEBUG((" out xrdp_mcs_disconnect")); + return 0; } diff --git a/libxrdp/xrdp_orders.c b/libxrdp/xrdp_orders.c index e7739e3e..438151da 100644 --- a/libxrdp/xrdp_orders.c +++ b/libxrdp/xrdp_orders.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - orders - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * orders + */ #include "libxrdp.h" @@ -28,138 +26,151 @@ #define LLOG_LEVEL 2 #define LLOGLN(_log_level, _params) \ -{ \ - if (_log_level < LLOG_LEVEL) \ - { \ - g_write("xrdp_orders.c [%10.10u]: ", g_time3()); \ - g_writeln _params ; \ - } \ -} + { \ + if (_log_level < LLOG_LEVEL) \ + { \ + g_write("xrdp_orders.c [%10.10u]: ", g_time3()); \ + g_writeln _params ; \ + } \ + } /*****************************************************************************/ -struct xrdp_orders* APP_CC -xrdp_orders_create(struct xrdp_session* session, struct xrdp_rdp* rdp_layer) +struct xrdp_orders *APP_CC +xrdp_orders_create(struct xrdp_session *session, struct xrdp_rdp *rdp_layer) { - struct xrdp_orders* self; + struct xrdp_orders *self; - self = (struct xrdp_orders*)g_malloc(sizeof(struct xrdp_orders), 1); - self->session = session; - self->rdp_layer = rdp_layer; - make_stream(self->out_s); - init_stream(self->out_s, 16384); - self->orders_state.clip_right = 1; /* silly rdp right clip */ - self->orders_state.clip_bottom = 1; /* silly rdp bottom clip */ - return self; + self = (struct xrdp_orders *)g_malloc(sizeof(struct xrdp_orders), 1); + self->session = session; + self->rdp_layer = rdp_layer; + make_stream(self->out_s); + init_stream(self->out_s, 16384); + self->orders_state.clip_right = 1; /* silly rdp right clip */ + self->orders_state.clip_bottom = 1; /* silly rdp bottom clip */ + return self; } /*****************************************************************************/ void APP_CC -xrdp_orders_delete(struct xrdp_orders* self) +xrdp_orders_delete(struct xrdp_orders *self) { - if (self == 0) - { - return; - } - free_stream(self->out_s); - g_free(self->orders_state.text_data); - g_free(self); + if (self == 0) + { + return; + } + + free_stream(self->out_s); + g_free(self->orders_state.text_data); + g_free(self); } /*****************************************************************************/ /* set all values to zero */ /* returns error */ int APP_CC -xrdp_orders_reset(struct xrdp_orders* self) +xrdp_orders_reset(struct xrdp_orders *self) { - if (xrdp_orders_force_send(self) != 0) - { - return 1; - } - g_free(self->orders_state.text_data); - g_memset(&(self->orders_state), 0, sizeof(self->orders_state)); - self->order_count_ptr = 0; - self->order_count = 0; - self->order_level = 0; - self->orders_state.clip_right = 1; /* silly rdp right clip */ - self->orders_state.clip_bottom = 1; /* silly rdp bottom clip */ - return 0; -} + if (xrdp_orders_force_send(self) != 0) + { + return 1; + } -/*****************************************************************************/ -/* returns error */ -int APP_CC -xrdp_orders_init(struct xrdp_orders* self) -{ - self->order_level++; - if (self->order_level == 1) - { + g_free(self->orders_state.text_data); + g_memset(&(self->orders_state), 0, sizeof(self->orders_state)); + self->order_count_ptr = 0; self->order_count = 0; - /* is this big enough */ - if (xrdp_rdp_init_data(self->rdp_layer, self->out_s) != 0) - { - return 1; - } - out_uint16_le(self->out_s, RDP_UPDATE_ORDERS); - out_uint8s(self->out_s, 2); /* pad */ - self->order_count_ptr = self->out_s->p; - out_uint8s(self->out_s, 2); /* number of orders, set later */ - out_uint8s(self->out_s, 2); /* pad */ - } - return 0; + self->order_level = 0; + self->orders_state.clip_right = 1; /* silly rdp right clip */ + self->orders_state.clip_bottom = 1; /* silly rdp bottom clip */ + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_orders_send(struct xrdp_orders* self) +xrdp_orders_init(struct xrdp_orders *self) { - int rv; + self->order_level++; - rv = 0; - if (self->order_level > 0) - { - self->order_level--; - if ((self->order_level == 0) && (self->order_count > 0)) + if (self->order_level == 1) { - s_mark_end(self->out_s); - DEBUG(("xrdp_orders_send sending %d orders", self->order_count)); - self->order_count_ptr[0] = self->order_count; - self->order_count_ptr[1] = self->order_count >> 8; - self->order_count = 0; - if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, - RDP_DATA_PDU_UPDATE) != 0) - { - rv = 1; - } + self->order_count = 0; + + /* is this big enough */ + if (xrdp_rdp_init_data(self->rdp_layer, self->out_s) != 0) + { + return 1; + } + + out_uint16_le(self->out_s, RDP_UPDATE_ORDERS); + out_uint8s(self->out_s, 2); /* pad */ + self->order_count_ptr = self->out_s->p; + out_uint8s(self->out_s, 2); /* number of orders, set later */ + out_uint8s(self->out_s, 2); /* pad */ } - } - return rv; + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_orders_force_send(struct xrdp_orders* self) +xrdp_orders_send(struct xrdp_orders *self) { - if (self == 0) - { - return 1; - } - if ((self->order_level > 0) && (self->order_count > 0)) - { - s_mark_end(self->out_s); - DEBUG(("xrdp_orders_force_send sending %d orders", self->order_count)); - self->order_count_ptr[0] = self->order_count; - self->order_count_ptr[1] = self->order_count >> 8; - if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, - RDP_DATA_PDU_UPDATE) != 0) + int rv; + + rv = 0; + + if (self->order_level > 0) { - return 1; + self->order_level--; + + if ((self->order_level == 0) && (self->order_count > 0)) + { + s_mark_end(self->out_s); + DEBUG(("xrdp_orders_send sending %d orders", self->order_count)); + self->order_count_ptr[0] = self->order_count; + self->order_count_ptr[1] = self->order_count >> 8; + self->order_count = 0; + + if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, + RDP_DATA_PDU_UPDATE) != 0) + { + rv = 1; + } + } } - } - self->order_count = 0; - self->order_level = 0; - return 0; + + return rv; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +xrdp_orders_force_send(struct xrdp_orders *self) +{ + if (self == 0) + { + return 1; + } + + if ((self->order_level > 0) && (self->order_count > 0)) + { + s_mark_end(self->out_s); + DEBUG(("xrdp_orders_force_send sending %d orders", self->order_count)); + self->order_count_ptr[0] = self->order_count; + self->order_count_ptr[1] = self->order_count >> 8; + + if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, + RDP_DATA_PDU_UPDATE) != 0) + { + return 1; + } + } + + self->order_count = 0; + self->order_level = 0; + return 0; } /*****************************************************************************/ @@ -167,232 +178,258 @@ xrdp_orders_force_send(struct xrdp_orders* self) /* send what we got and init a new one */ /* returns error */ int APP_CC -xrdp_orders_check(struct xrdp_orders* self, int max_size) +xrdp_orders_check(struct xrdp_orders *self, int max_size) { - int size; - int max_packet_size; + int size; + int max_packet_size; - if (self->rdp_layer->client_info.bpp == 8) - { - max_packet_size = 8000; - } - else - { - max_packet_size = 16000; - } - if (self->order_level < 1) - { - if (max_size > max_packet_size) + if (self->rdp_layer->client_info.bpp == 8) { - return 1; + max_packet_size = 8000; } else { - return 0; + max_packet_size = 16000; } - } - size = (int)(self->out_s->p - self->order_count_ptr); - if ((size < 0) || (size > max_packet_size)) - { - return 1; - } - if ((size + max_size + 100) > max_packet_size) - { - xrdp_orders_force_send(self); - xrdp_orders_init(self); - } - return 0; + + if (self->order_level < 1) + { + if (max_size > max_packet_size) + { + return 1; + } + else + { + return 0; + } + } + + size = (int)(self->out_s->p - self->order_count_ptr); + + if ((size < 0) || (size > max_packet_size)) + { + return 1; + } + + if ((size + max_size + 100) > max_packet_size) + { + xrdp_orders_force_send(self); + xrdp_orders_init(self); + } + + return 0; } /*****************************************************************************/ /* check if rect is the same as the last one sent */ /* returns boolean */ static int APP_CC -xrdp_orders_last_bounds(struct xrdp_orders* self, struct xrdp_rect* rect) +xrdp_orders_last_bounds(struct xrdp_orders *self, struct xrdp_rect *rect) { - if (rect == 0) - { + if (rect == 0) + { + return 0; + } + + if ((rect->left == self->orders_state.clip_left) && + (rect->top == self->orders_state.clip_top) && + (rect->right == self->orders_state.clip_right) && + (rect->bottom == self->orders_state.clip_bottom)) + { + return 1; + } + return 0; - } - if ((rect->left == self->orders_state.clip_left) && - (rect->top == self->orders_state.clip_top) && - (rect->right == self->orders_state.clip_right) && - (rect->bottom == self->orders_state.clip_bottom)) - { - return 1; - } - return 0; } /*****************************************************************************/ /* check if all coords are withing 256 bytes */ /* returns boolean */ static int APP_CC -xrdp_orders_send_delta(struct xrdp_orders* self, int* vals, int count) +xrdp_orders_send_delta(struct xrdp_orders *self, int *vals, int count) { - int i; + int i; - for (i = 0; i < count; i += 2) - { - if (g_abs(vals[i] - vals[i + 1]) >= 128) + for (i = 0; i < count; i += 2) { - return 0; + if (g_abs(vals[i] - vals[i + 1]) >= 128) + { + return 0; + } } - } - return 1; + + return 1; } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_orders_out_bounds(struct xrdp_orders* self, struct xrdp_rect* rect) +xrdp_orders_out_bounds(struct xrdp_orders *self, struct xrdp_rect *rect) { - char* bounds_flags_ptr; - int bounds_flags; + char *bounds_flags_ptr; + int bounds_flags; - bounds_flags = 0; - bounds_flags_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - /* left */ - if (rect->left == self->orders_state.clip_left) - { - } - else if (g_abs(rect->left - self->orders_state.clip_left) < 128) - { - bounds_flags |= 0x10; - } - else - { - bounds_flags |= 0x01; - } - /* top */ - if (rect->top == self->orders_state.clip_top) - { - } - else if (g_abs(rect->top - self->orders_state.clip_top) < 128) - { - bounds_flags |= 0x20; - } - else - { - bounds_flags |= 0x02; - } - /* right */ - if (rect->right == self->orders_state.clip_right) - { - } - else if (g_abs(rect->right - self->orders_state.clip_right) < 128) - { - bounds_flags |= 0x40; - } - else - { - bounds_flags |= 0x04; - } - /* bottom */ - if (rect->bottom == self->orders_state.clip_bottom) - { - } - else if (g_abs(rect->bottom - self->orders_state.clip_bottom) < 128) - { - bounds_flags |= 0x80; - } - else - { - bounds_flags |= 0x08; - } - /* left */ - if (bounds_flags & 0x01) - { - out_uint16_le(self->out_s, rect->left); - } - else if (bounds_flags & 0x10) - { - out_uint8(self->out_s, rect->left - self->orders_state.clip_left); - } - self->orders_state.clip_left = rect->left; - /* top */ - if (bounds_flags & 0x02) - { - out_uint16_le(self->out_s, rect->top); - } - else if (bounds_flags & 0x20) - { - out_uint8(self->out_s, rect->top - self->orders_state.clip_top); - } - self->orders_state.clip_top = rect->top; - /* right */ - if (bounds_flags & 0x04) - { - out_uint16_le(self->out_s, rect->right - 1); /* silly rdp right clip */ - } - else if (bounds_flags & 0x40) - { - out_uint8(self->out_s, rect->right - self->orders_state.clip_right); - } - self->orders_state.clip_right = rect->right; - /* bottom */ - if (bounds_flags & 0x08) - { - out_uint16_le(self->out_s, rect->bottom - 1); /* silly rdp bottom clip */ - } - else if (bounds_flags & 0x80) - { - out_uint8(self->out_s, rect->bottom - self->orders_state.clip_bottom); - } - self->orders_state.clip_bottom = rect->bottom; - /* set flags */ - *bounds_flags_ptr = bounds_flags; - return 0; + bounds_flags = 0; + bounds_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + /* left */ + if (rect->left == self->orders_state.clip_left) + { + } + else if (g_abs(rect->left - self->orders_state.clip_left) < 128) + { + bounds_flags |= 0x10; + } + else + { + bounds_flags |= 0x01; + } + + /* top */ + if (rect->top == self->orders_state.clip_top) + { + } + else if (g_abs(rect->top - self->orders_state.clip_top) < 128) + { + bounds_flags |= 0x20; + } + else + { + bounds_flags |= 0x02; + } + + /* right */ + if (rect->right == self->orders_state.clip_right) + { + } + else if (g_abs(rect->right - self->orders_state.clip_right) < 128) + { + bounds_flags |= 0x40; + } + else + { + bounds_flags |= 0x04; + } + + /* bottom */ + if (rect->bottom == self->orders_state.clip_bottom) + { + } + else if (g_abs(rect->bottom - self->orders_state.clip_bottom) < 128) + { + bounds_flags |= 0x80; + } + else + { + bounds_flags |= 0x08; + } + + /* left */ + if (bounds_flags & 0x01) + { + out_uint16_le(self->out_s, rect->left); + } + else if (bounds_flags & 0x10) + { + out_uint8(self->out_s, rect->left - self->orders_state.clip_left); + } + + self->orders_state.clip_left = rect->left; + + /* top */ + if (bounds_flags & 0x02) + { + out_uint16_le(self->out_s, rect->top); + } + else if (bounds_flags & 0x20) + { + out_uint8(self->out_s, rect->top - self->orders_state.clip_top); + } + + self->orders_state.clip_top = rect->top; + + /* right */ + if (bounds_flags & 0x04) + { + out_uint16_le(self->out_s, rect->right - 1); /* silly rdp right clip */ + } + else if (bounds_flags & 0x40) + { + out_uint8(self->out_s, rect->right - self->orders_state.clip_right); + } + + self->orders_state.clip_right = rect->right; + + /* bottom */ + if (bounds_flags & 0x08) + { + out_uint16_le(self->out_s, rect->bottom - 1); /* silly rdp bottom clip */ + } + else if (bounds_flags & 0x80) + { + out_uint8(self->out_s, rect->bottom - self->orders_state.clip_bottom); + } + + self->orders_state.clip_bottom = rect->bottom; + /* set flags */ + *bounds_flags_ptr = bounds_flags; + return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_order_pack_small_or_tiny(struct xrdp_orders* self, - char* order_flags_ptr, int orders_flags, - char* present_ptr, int present, +xrdp_order_pack_small_or_tiny(struct xrdp_orders *self, + char *order_flags_ptr, int orders_flags, + char *present_ptr, int present, int present_size) { - int move_up_count = 0; - int index = 0; - int size = 0; - int keep_looking = 1; + int move_up_count = 0; + int index = 0; + int size = 0; + int keep_looking = 1; - move_up_count = 0; - keep_looking = 1; - for (index = present_size - 1; index >= 0; index--) - { - if (keep_looking) + move_up_count = 0; + keep_looking = 1; + + for (index = present_size - 1; index >= 0; index--) { - if (((present >> (index * 8)) & 0xff) == 0) - { - move_up_count++; - } - else - { - keep_looking = 0; - } + if (keep_looking) + { + if (((present >> (index * 8)) & 0xff) == 0) + { + move_up_count++; + } + else + { + keep_looking = 0; + } + } + + present_ptr[index] = present >> (index * 8); } - present_ptr[index] = present >> (index * 8); - } - if (move_up_count > 0) - { - /* move_up_count should be 0, 1, 2, or 3 - shifting it 6 will make it RDP_ORDER_TINY(0x80) or - RDP_ORDER_SMALL(0x40) or both */ - orders_flags |= move_up_count << 6; - size = (int)(self->out_s->p - present_ptr); - size -= present_size; - for (index = 0; index < size; index++) + + if (move_up_count > 0) { - present_ptr[index + (present_size - move_up_count)] = - present_ptr[index + present_size]; + /* move_up_count should be 0, 1, 2, or 3 + shifting it 6 will make it RDP_ORDER_TINY(0x80) or + RDP_ORDER_SMALL(0x40) or both */ + orders_flags |= move_up_count << 6; + size = (int)(self->out_s->p - present_ptr); + size -= present_size; + + for (index = 0; index < size; index++) + { + present_ptr[index + (present_size - move_up_count)] = + present_ptr[index + present_size]; + } + + self->out_s->p -= move_up_count; } - self->out_s->p -= move_up_count; - } - order_flags_ptr[0] = orders_flags; - return 0; + + order_flags_ptr[0] = orders_flags; + return 0; } /*****************************************************************************/ @@ -400,140 +437,166 @@ xrdp_order_pack_small_or_tiny(struct xrdp_orders* self, /* send a solid rect to client */ /* max size 23 */ int APP_CC -xrdp_orders_rect(struct xrdp_orders* self, int x, int y, int cx, int cy, - int color, struct xrdp_rect* rect) +xrdp_orders_rect(struct xrdp_orders *self, int x, int y, int cx, int cy, + int color, struct xrdp_rect *rect) { - int order_flags; - int vals[8]; - int present; - char* present_ptr; - char* order_flags_ptr; + int order_flags; + int vals[8]; + int present; + char *present_ptr; + char *order_flags_ptr; - xrdp_orders_check(self, 23); - self->order_count++; - order_flags = RDP_ORDER_STANDARD; - if (self->orders_state.last_order != RDP_ORDER_RECT) - { - order_flags |= RDP_ORDER_CHANGE; - } - self->orders_state.last_order = RDP_ORDER_RECT; - if (rect != 0) - { - /* if clip is present, still check if its needed */ - if (x < rect->left || y < rect->top || - x + cx > rect->right || y + cy > rect->bottom) + xrdp_orders_check(self, 23); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + + if (self->orders_state.last_order != RDP_ORDER_RECT) { - order_flags |= RDP_ORDER_BOUNDS; - if (xrdp_orders_last_bounds(self, rect)) - { - order_flags |= RDP_ORDER_LASTBOUNDS; - } + order_flags |= RDP_ORDER_CHANGE; } - } - vals[0] = x; - vals[1] = self->orders_state.rect_x; - vals[2] = y; - vals[3] = self->orders_state.rect_y; - vals[4] = cx; - vals[5] = self->orders_state.rect_cx; - vals[6] = cy; - vals[7] = self->orders_state.rect_cy; - if (xrdp_orders_send_delta(self, vals, 8)) - { - order_flags |= RDP_ORDER_DELTA; - } - /* order_flags, set later, 1 byte */ - order_flags_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if (order_flags & RDP_ORDER_CHANGE) - { - out_uint8(self->out_s, self->orders_state.last_order); - } - present = 0; - /* present, set later, 1 byte */ - present_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if ((order_flags & RDP_ORDER_BOUNDS) && - !(order_flags & RDP_ORDER_LASTBOUNDS)) - { - xrdp_orders_out_bounds(self, rect); - } - if (x != self->orders_state.rect_x) - { - present |= 0x01; - if (order_flags & RDP_ORDER_DELTA) + + self->orders_state.last_order = RDP_ORDER_RECT; + + if (rect != 0) { - out_uint8(self->out_s, x - self->orders_state.rect_x); + /* if clip is present, still check if its needed */ + if (x < rect->left || y < rect->top || + x + cx > rect->right || y + cy > rect->bottom) + { + order_flags |= RDP_ORDER_BOUNDS; + + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } } - else + + vals[0] = x; + vals[1] = self->orders_state.rect_x; + vals[2] = y; + vals[3] = self->orders_state.rect_y; + vals[4] = cx; + vals[5] = self->orders_state.rect_cx; + vals[6] = cy; + vals[7] = self->orders_state.rect_cy; + + if (xrdp_orders_send_delta(self, vals, 8)) { - out_uint16_le(self->out_s, x); + order_flags |= RDP_ORDER_DELTA; } - self->orders_state.rect_x = x; - } - if (y != self->orders_state.rect_y) - { - present |= 0x02; - if (order_flags & RDP_ORDER_DELTA) + + /* order_flags, set later, 1 byte */ + order_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if (order_flags & RDP_ORDER_CHANGE) { - out_uint8(self->out_s, y - self->orders_state.rect_y); + out_uint8(self->out_s, self->orders_state.last_order); } - else + + present = 0; + /* present, set later, 1 byte */ + present_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) { - out_uint16_le(self->out_s, y); + xrdp_orders_out_bounds(self, rect); } - self->orders_state.rect_y = y; - } - if (cx != self->orders_state.rect_cx) - { - present |= 0x04; - if (order_flags & RDP_ORDER_DELTA) + + if (x != self->orders_state.rect_x) { - out_uint8(self->out_s, cx - self->orders_state.rect_cx); + present |= 0x01; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->orders_state.rect_x); + } + else + { + out_uint16_le(self->out_s, x); + } + + self->orders_state.rect_x = x; } - else + + if (y != self->orders_state.rect_y) { - out_uint16_le(self->out_s, cx); + present |= 0x02; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->orders_state.rect_y); + } + else + { + out_uint16_le(self->out_s, y); + } + + self->orders_state.rect_y = y; } - self->orders_state.rect_cx = cx; - } - if (cy != self->orders_state.rect_cy) - { - present |= 0x08; - if (order_flags & RDP_ORDER_DELTA) + + if (cx != self->orders_state.rect_cx) { - out_uint8(self->out_s, cy - self->orders_state.rect_cy); + present |= 0x04; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->orders_state.rect_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + + self->orders_state.rect_cx = cx; } - else + + if (cy != self->orders_state.rect_cy) { - out_uint16_le(self->out_s, cy); + present |= 0x08; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->orders_state.rect_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + + self->orders_state.rect_cy = cy; } - self->orders_state.rect_cy = cy; - } - if ((color & 0xff) != (self->orders_state.rect_color & 0xff)) - { - present |= 0x10; - self->orders_state.rect_color = - (self->orders_state.rect_color & 0xffff00) | (color & 0xff); - out_uint8(self->out_s, color); - } - if ((color & 0xff00) != (self->orders_state.rect_color & 0xff00)) - { - present |= 0x20; - self->orders_state.rect_color = - (self->orders_state.rect_color & 0xff00ff) | (color & 0xff00); - out_uint8(self->out_s, color >> 8); - } - if ((color & 0xff0000) != (self->orders_state.rect_color & 0xff0000)) - { - present |= 0x40; - self->orders_state.rect_color = - (self->orders_state.rect_color & 0x00ffff) | (color & 0xff0000); - out_uint8(self->out_s, color >> 16); - } - xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, - present_ptr, present, 1); - return 0; + + if ((color & 0xff) != (self->orders_state.rect_color & 0xff)) + { + present |= 0x10; + self->orders_state.rect_color = + (self->orders_state.rect_color & 0xffff00) | (color & 0xff); + out_uint8(self->out_s, color); + } + + if ((color & 0xff00) != (self->orders_state.rect_color & 0xff00)) + { + present |= 0x20; + self->orders_state.rect_color = + (self->orders_state.rect_color & 0xff00ff) | (color & 0xff00); + out_uint8(self->out_s, color >> 8); + } + + if ((color & 0xff0000) != (self->orders_state.rect_color & 0xff0000)) + { + present |= 0x40; + self->orders_state.rect_color = + (self->orders_state.rect_color & 0x00ffff) | (color & 0xff0000); + out_uint8(self->out_s, color >> 16); + } + + xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, + present_ptr, present, 1); + return 0; } /*****************************************************************************/ @@ -541,156 +604,186 @@ xrdp_orders_rect(struct xrdp_orders* self, int x, int y, int cx, int cy, /* send a screen blt order */ /* max size 25 */ int APP_CC -xrdp_orders_screen_blt(struct xrdp_orders* self, int x, int y, +xrdp_orders_screen_blt(struct xrdp_orders *self, int x, int y, int cx, int cy, int srcx, int srcy, - int rop, struct xrdp_rect* rect) + int rop, struct xrdp_rect *rect) { - int order_flags = 0; - int vals[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - int present = 0; - char* present_ptr = (char *)NULL; - char* order_flags_ptr = (char *)NULL; + int order_flags = 0; + int vals[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int present = 0; + char *present_ptr = (char *)NULL; + char *order_flags_ptr = (char *)NULL; - xrdp_orders_check(self, 25); - self->order_count++; - order_flags = RDP_ORDER_STANDARD; - if (self->orders_state.last_order != RDP_ORDER_SCREENBLT) - { - order_flags |= RDP_ORDER_CHANGE; - } - self->orders_state.last_order = RDP_ORDER_SCREENBLT; - if (rect != 0) - { - /* if clip is present, still check if its needed */ - if (x < rect->left || y < rect->top || - x + cx > rect->right || y + cy > rect->bottom) + xrdp_orders_check(self, 25); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + + if (self->orders_state.last_order != RDP_ORDER_SCREENBLT) { - order_flags |= RDP_ORDER_BOUNDS; - if (xrdp_orders_last_bounds(self, rect)) - { - order_flags |= RDP_ORDER_LASTBOUNDS; - } + order_flags |= RDP_ORDER_CHANGE; } - } - vals[0] = x; - vals[1] = self->orders_state.scr_blt_x; - vals[2] = y; - vals[3] = self->orders_state.scr_blt_y; - vals[4] = cx; - vals[5] = self->orders_state.scr_blt_cx; - vals[6] = cy; - vals[7] = self->orders_state.scr_blt_cy; - vals[8] = srcx; - vals[9] = self->orders_state.scr_blt_srcx; - vals[10] = srcy; - vals[11] = self->orders_state.scr_blt_srcy; - if (xrdp_orders_send_delta(self, vals, 12)) - { - order_flags |= RDP_ORDER_DELTA; - } - /* order_flags, set later, 1 byte */ - order_flags_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if (order_flags & RDP_ORDER_CHANGE) - { - out_uint8(self->out_s, self->orders_state.last_order); - } - present = 0; - /* present, set later, 1 byte */ - present_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if ((order_flags & RDP_ORDER_BOUNDS) && - !(order_flags & RDP_ORDER_LASTBOUNDS)) - { - xrdp_orders_out_bounds(self, rect); - } - if (x != self->orders_state.scr_blt_x) - { - present |= 0x01; - if (order_flags & RDP_ORDER_DELTA) + + self->orders_state.last_order = RDP_ORDER_SCREENBLT; + + if (rect != 0) { - out_uint8(self->out_s, x - self->orders_state.scr_blt_x); + /* if clip is present, still check if its needed */ + if (x < rect->left || y < rect->top || + x + cx > rect->right || y + cy > rect->bottom) + { + order_flags |= RDP_ORDER_BOUNDS; + + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } } - else + + vals[0] = x; + vals[1] = self->orders_state.scr_blt_x; + vals[2] = y; + vals[3] = self->orders_state.scr_blt_y; + vals[4] = cx; + vals[5] = self->orders_state.scr_blt_cx; + vals[6] = cy; + vals[7] = self->orders_state.scr_blt_cy; + vals[8] = srcx; + vals[9] = self->orders_state.scr_blt_srcx; + vals[10] = srcy; + vals[11] = self->orders_state.scr_blt_srcy; + + if (xrdp_orders_send_delta(self, vals, 12)) { - out_uint16_le(self->out_s, x); + order_flags |= RDP_ORDER_DELTA; } - self->orders_state.scr_blt_x = x; - } - if (y != self->orders_state.scr_blt_y) - { - present |= 0x02; - if (order_flags & RDP_ORDER_DELTA) + + /* order_flags, set later, 1 byte */ + order_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if (order_flags & RDP_ORDER_CHANGE) { - out_uint8(self->out_s, y - self->orders_state.scr_blt_y); + out_uint8(self->out_s, self->orders_state.last_order); } - else + + present = 0; + /* present, set later, 1 byte */ + present_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) { - out_uint16_le(self->out_s, y); + xrdp_orders_out_bounds(self, rect); } - self->orders_state.scr_blt_y = y; - } - if (cx != self->orders_state.scr_blt_cx) - { - present |= 0x04; - if (order_flags & RDP_ORDER_DELTA) + + if (x != self->orders_state.scr_blt_x) { - out_uint8(self->out_s, cx - self->orders_state.scr_blt_cx); + present |= 0x01; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->orders_state.scr_blt_x); + } + else + { + out_uint16_le(self->out_s, x); + } + + self->orders_state.scr_blt_x = x; } - else + + if (y != self->orders_state.scr_blt_y) { - out_uint16_le(self->out_s, cx); + present |= 0x02; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->orders_state.scr_blt_y); + } + else + { + out_uint16_le(self->out_s, y); + } + + self->orders_state.scr_blt_y = y; } - self->orders_state.scr_blt_cx = cx; - } - if (cy != self->orders_state.scr_blt_cy) - { - present |= 0x08; - if (order_flags & RDP_ORDER_DELTA) + + if (cx != self->orders_state.scr_blt_cx) { - out_uint8(self->out_s, cy - self->orders_state.scr_blt_cy); + present |= 0x04; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->orders_state.scr_blt_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + + self->orders_state.scr_blt_cx = cx; } - else + + if (cy != self->orders_state.scr_blt_cy) { - out_uint16_le(self->out_s, cy); + present |= 0x08; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->orders_state.scr_blt_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + + self->orders_state.scr_blt_cy = cy; } - self->orders_state.scr_blt_cy = cy; - } - if (rop != self->orders_state.scr_blt_rop) - { - present |= 0x10; - out_uint8(self->out_s, rop); - self->orders_state.scr_blt_rop = rop; - } - if (srcx != self->orders_state.scr_blt_srcx) - { - present |= 0x20; - if (order_flags & RDP_ORDER_DELTA) + + if (rop != self->orders_state.scr_blt_rop) { - out_uint8(self->out_s, srcx - self->orders_state.scr_blt_srcx); + present |= 0x10; + out_uint8(self->out_s, rop); + self->orders_state.scr_blt_rop = rop; } - else + + if (srcx != self->orders_state.scr_blt_srcx) { - out_uint16_le(self->out_s, srcx); + present |= 0x20; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcx - self->orders_state.scr_blt_srcx); + } + else + { + out_uint16_le(self->out_s, srcx); + } + + self->orders_state.scr_blt_srcx = srcx; } - self->orders_state.scr_blt_srcx = srcx; - } - if (srcy != self->orders_state.scr_blt_srcy) - { - present |= 0x40; - if (order_flags & RDP_ORDER_DELTA) + + if (srcy != self->orders_state.scr_blt_srcy) { - out_uint8(self->out_s, srcy - self->orders_state.scr_blt_srcy); + present |= 0x40; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcy - self->orders_state.scr_blt_srcy); + } + else + { + out_uint16_le(self->out_s, srcy); + } + + self->orders_state.scr_blt_srcy = srcy; } - else - { - out_uint16_le(self->out_s, srcy); - } - self->orders_state.scr_blt_srcy = srcy; - } - xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, - present_ptr, present, 1); - return 0; + + xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, + present_ptr, present, 1); + return 0; } /*****************************************************************************/ @@ -698,182 +791,215 @@ xrdp_orders_screen_blt(struct xrdp_orders* self, int x, int y, /* send a pat blt order */ /* max size 39 */ int APP_CC -xrdp_orders_pat_blt(struct xrdp_orders* self, int x, int y, +xrdp_orders_pat_blt(struct xrdp_orders *self, int x, int y, int cx, int cy, int rop, int bg_color, - int fg_color, struct xrdp_brush* brush, - struct xrdp_rect* rect) + int fg_color, struct xrdp_brush *brush, + struct xrdp_rect *rect) { - int order_flags; - int present; - int vals[8]; - char* present_ptr; - char* order_flags_ptr; - struct xrdp_brush blank_brush; + int order_flags; + int present; + int vals[8]; + char *present_ptr; + char *order_flags_ptr; + struct xrdp_brush blank_brush; - xrdp_orders_check(self, 39); - self->order_count++; - order_flags = RDP_ORDER_STANDARD; - if (self->orders_state.last_order != RDP_ORDER_PATBLT) - { - order_flags |= RDP_ORDER_CHANGE; - } - self->orders_state.last_order = RDP_ORDER_PATBLT; - if (rect != 0) - { - /* if clip is present, still check if its needed */ - if (x < rect->left || y < rect->top || - x + cx > rect->right || y + cy > rect->bottom) + xrdp_orders_check(self, 39); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + + if (self->orders_state.last_order != RDP_ORDER_PATBLT) { - order_flags |= RDP_ORDER_BOUNDS; - if (xrdp_orders_last_bounds(self, rect)) - { - order_flags |= RDP_ORDER_LASTBOUNDS; - } + order_flags |= RDP_ORDER_CHANGE; } - } - vals[0] = x; - vals[1] = self->orders_state.pat_blt_x; - vals[2] = y; - vals[3] = self->orders_state.pat_blt_y; - vals[4] = cx; - vals[5] = self->orders_state.pat_blt_cx; - vals[6] = cy; - vals[7] = self->orders_state.pat_blt_cy; - if (xrdp_orders_send_delta(self, vals, 8)) - { - order_flags |= RDP_ORDER_DELTA; - } - /* order_flags, set later, 1 byte */ - order_flags_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if (order_flags & RDP_ORDER_CHANGE) - { - out_uint8(self->out_s, self->orders_state.last_order); - } - present = 0; - /* present, set later, 2 bytes */ - present_ptr = self->out_s->p; - out_uint8s(self->out_s, 2); - if ((order_flags & RDP_ORDER_BOUNDS) && - !(order_flags & RDP_ORDER_LASTBOUNDS)) - { - xrdp_orders_out_bounds(self, rect); - } - if (x != self->orders_state.pat_blt_x) - { - present |= 0x0001; - if (order_flags & RDP_ORDER_DELTA) + + self->orders_state.last_order = RDP_ORDER_PATBLT; + + if (rect != 0) { - out_uint8(self->out_s, x - self->orders_state.pat_blt_x); + /* if clip is present, still check if its needed */ + if (x < rect->left || y < rect->top || + x + cx > rect->right || y + cy > rect->bottom) + { + order_flags |= RDP_ORDER_BOUNDS; + + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } } - else + + vals[0] = x; + vals[1] = self->orders_state.pat_blt_x; + vals[2] = y; + vals[3] = self->orders_state.pat_blt_y; + vals[4] = cx; + vals[5] = self->orders_state.pat_blt_cx; + vals[6] = cy; + vals[7] = self->orders_state.pat_blt_cy; + + if (xrdp_orders_send_delta(self, vals, 8)) { - out_uint16_le(self->out_s, x); + order_flags |= RDP_ORDER_DELTA; } - self->orders_state.pat_blt_x = x; - } - if (y != self->orders_state.pat_blt_y) - { - present |= 0x0002; - if (order_flags & RDP_ORDER_DELTA) + + /* order_flags, set later, 1 byte */ + order_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if (order_flags & RDP_ORDER_CHANGE) { - out_uint8(self->out_s, y - self->orders_state.pat_blt_y); + out_uint8(self->out_s, self->orders_state.last_order); } - else + + present = 0; + /* present, set later, 2 bytes */ + present_ptr = self->out_s->p; + out_uint8s(self->out_s, 2); + + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) { - out_uint16_le(self->out_s, y); + xrdp_orders_out_bounds(self, rect); } - self->orders_state.pat_blt_y = y; - } - if (cx != self->orders_state.pat_blt_cx) - { - present |= 0x0004; - if (order_flags & RDP_ORDER_DELTA) + + if (x != self->orders_state.pat_blt_x) { - out_uint8(self->out_s, cx - self->orders_state.pat_blt_cx); + present |= 0x0001; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->orders_state.pat_blt_x); + } + else + { + out_uint16_le(self->out_s, x); + } + + self->orders_state.pat_blt_x = x; } - else + + if (y != self->orders_state.pat_blt_y) { - out_uint16_le(self->out_s, cx); + present |= 0x0002; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->orders_state.pat_blt_y); + } + else + { + out_uint16_le(self->out_s, y); + } + + self->orders_state.pat_blt_y = y; } - self->orders_state.pat_blt_cx = cx; - } - if (cy != self->orders_state.pat_blt_cy) - { - present |= 0x0008; - if (order_flags & RDP_ORDER_DELTA) + + if (cx != self->orders_state.pat_blt_cx) { - out_uint8(self->out_s, cy - self->orders_state.pat_blt_cy); + present |= 0x0004; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->orders_state.pat_blt_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + + self->orders_state.pat_blt_cx = cx; } - else + + if (cy != self->orders_state.pat_blt_cy) { - out_uint16_le(self->out_s, cy); + present |= 0x0008; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->orders_state.pat_blt_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + + self->orders_state.pat_blt_cy = cy; } - self->orders_state.pat_blt_cy = cy; - } - if (rop != self->orders_state.pat_blt_rop) - { - present |= 0x0010; - /* PATCOPY PATPAINT PATINVERT DSTINVERT BLACKNESS WHITENESS */ - out_uint8(self->out_s, rop); - self->orders_state.pat_blt_rop = rop; - } - if (bg_color != self->orders_state.pat_blt_bg_color) - { - present |= 0x0020; - out_uint8(self->out_s, bg_color); - out_uint8(self->out_s, bg_color >> 8); - out_uint8(self->out_s, bg_color >> 16); - self->orders_state.pat_blt_bg_color = bg_color; - } - if (fg_color != self->orders_state.pat_blt_fg_color) - { - present |= 0x0040; - out_uint8(self->out_s, fg_color); - out_uint8(self->out_s, fg_color >> 8); - out_uint8(self->out_s, fg_color >> 16); - self->orders_state.pat_blt_fg_color = fg_color; - } - if (brush == 0) /* if nil use blank one */ - { /* todo can we just set style to zero */ - g_memset(&blank_brush, 0, sizeof(struct xrdp_brush)); - brush = &blank_brush; - } - if (brush->x_orgin != self->orders_state.pat_blt_brush.x_orgin) - { - present |= 0x0080; - out_uint8(self->out_s, brush->x_orgin); - self->orders_state.pat_blt_brush.x_orgin = brush->x_orgin; - } - if (brush->y_orgin != self->orders_state.pat_blt_brush.y_orgin) - { - present |= 0x0100; - out_uint8(self->out_s, brush->y_orgin); - self->orders_state.pat_blt_brush.y_orgin = brush->y_orgin; - } - if (brush->style != self->orders_state.pat_blt_brush.style) - { - present |= 0x0200; - out_uint8(self->out_s, brush->style); - self->orders_state.pat_blt_brush.style = brush->style; - } - if (brush->pattern[0] != self->orders_state.pat_blt_brush.pattern[0]) - { - present |= 0x0400; - out_uint8(self->out_s, brush->pattern[0]); - self->orders_state.pat_blt_brush.pattern[0] = brush->pattern[0]; - } - if (g_memcmp(brush->pattern + 1, - self->orders_state.pat_blt_brush.pattern + 1, 7) != 0) - { - present |= 0x0800; - out_uint8a(self->out_s, brush->pattern + 1, 7); - g_memcpy(self->orders_state.pat_blt_brush.pattern + 1, - brush->pattern + 1, 7); - } - xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, - present_ptr, present, 2); - return 0; + + if (rop != self->orders_state.pat_blt_rop) + { + present |= 0x0010; + /* PATCOPY PATPAINT PATINVERT DSTINVERT BLACKNESS WHITENESS */ + out_uint8(self->out_s, rop); + self->orders_state.pat_blt_rop = rop; + } + + if (bg_color != self->orders_state.pat_blt_bg_color) + { + present |= 0x0020; + out_uint8(self->out_s, bg_color); + out_uint8(self->out_s, bg_color >> 8); + out_uint8(self->out_s, bg_color >> 16); + self->orders_state.pat_blt_bg_color = bg_color; + } + + if (fg_color != self->orders_state.pat_blt_fg_color) + { + present |= 0x0040; + out_uint8(self->out_s, fg_color); + out_uint8(self->out_s, fg_color >> 8); + out_uint8(self->out_s, fg_color >> 16); + self->orders_state.pat_blt_fg_color = fg_color; + } + + if (brush == 0) /* if nil use blank one */ + { + /* todo can we just set style to zero */ + g_memset(&blank_brush, 0, sizeof(struct xrdp_brush)); + brush = &blank_brush; + } + + if (brush->x_orgin != self->orders_state.pat_blt_brush.x_orgin) + { + present |= 0x0080; + out_uint8(self->out_s, brush->x_orgin); + self->orders_state.pat_blt_brush.x_orgin = brush->x_orgin; + } + + if (brush->y_orgin != self->orders_state.pat_blt_brush.y_orgin) + { + present |= 0x0100; + out_uint8(self->out_s, brush->y_orgin); + self->orders_state.pat_blt_brush.y_orgin = brush->y_orgin; + } + + if (brush->style != self->orders_state.pat_blt_brush.style) + { + present |= 0x0200; + out_uint8(self->out_s, brush->style); + self->orders_state.pat_blt_brush.style = brush->style; + } + + if (brush->pattern[0] != self->orders_state.pat_blt_brush.pattern[0]) + { + present |= 0x0400; + out_uint8(self->out_s, brush->pattern[0]); + self->orders_state.pat_blt_brush.pattern[0] = brush->pattern[0]; + } + + if (g_memcmp(brush->pattern + 1, + self->orders_state.pat_blt_brush.pattern + 1, 7) != 0) + { + present |= 0x0800; + out_uint8a(self->out_s, brush->pattern + 1, 7); + g_memcpy(self->orders_state.pat_blt_brush.pattern + 1, + brush->pattern + 1, 7); + } + + xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, + present_ptr, present, 2); + return 0; } /*****************************************************************************/ @@ -881,126 +1007,150 @@ xrdp_orders_pat_blt(struct xrdp_orders* self, int x, int y, /* send a dest blt order */ /* max size 21 */ int APP_CC -xrdp_orders_dest_blt(struct xrdp_orders* self, int x, int y, +xrdp_orders_dest_blt(struct xrdp_orders *self, int x, int y, int cx, int cy, int rop, - struct xrdp_rect* rect) + struct xrdp_rect *rect) { - int order_flags; - int vals[8]; - int present; - char* present_ptr; - char* order_flags_ptr; + int order_flags; + int vals[8]; + int present; + char *present_ptr; + char *order_flags_ptr; - xrdp_orders_check(self, 21); - self->order_count++; - order_flags = RDP_ORDER_STANDARD; - if (self->orders_state.last_order != RDP_ORDER_DESTBLT) - { - order_flags |= RDP_ORDER_CHANGE; - } - self->orders_state.last_order = RDP_ORDER_DESTBLT; - if (rect != 0) - { - /* if clip is present, still check if its needed */ - if (x < rect->left || y < rect->top || - x + cx > rect->right || y + cy > rect->bottom) + xrdp_orders_check(self, 21); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + + if (self->orders_state.last_order != RDP_ORDER_DESTBLT) { - order_flags |= RDP_ORDER_BOUNDS; - if (xrdp_orders_last_bounds(self, rect)) - { - order_flags |= RDP_ORDER_LASTBOUNDS; - } + order_flags |= RDP_ORDER_CHANGE; } - } - vals[0] = x; - vals[1] = self->orders_state.dest_blt_x; - vals[2] = y; - vals[3] = self->orders_state.dest_blt_y; - vals[4] = cx; - vals[5] = self->orders_state.dest_blt_cx; - vals[6] = cy; - vals[7] = self->orders_state.dest_blt_cy; - if (xrdp_orders_send_delta(self, vals, 8)) - { - order_flags |= RDP_ORDER_DELTA; - } - /* order_flags, set later, 1 byte */ - order_flags_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if (order_flags & RDP_ORDER_CHANGE) - { - out_uint8(self->out_s, self->orders_state.last_order); - } - present = 0; - /* present, set later, 1 byte */ - present_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if ((order_flags & RDP_ORDER_BOUNDS) && - !(order_flags & RDP_ORDER_LASTBOUNDS)) - { - xrdp_orders_out_bounds(self, rect); - } - if (x != self->orders_state.dest_blt_x) - { - present |= 0x01; - if (order_flags & RDP_ORDER_DELTA) + + self->orders_state.last_order = RDP_ORDER_DESTBLT; + + if (rect != 0) { - out_uint8(self->out_s, x - self->orders_state.dest_blt_x); + /* if clip is present, still check if its needed */ + if (x < rect->left || y < rect->top || + x + cx > rect->right || y + cy > rect->bottom) + { + order_flags |= RDP_ORDER_BOUNDS; + + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } } - else + + vals[0] = x; + vals[1] = self->orders_state.dest_blt_x; + vals[2] = y; + vals[3] = self->orders_state.dest_blt_y; + vals[4] = cx; + vals[5] = self->orders_state.dest_blt_cx; + vals[6] = cy; + vals[7] = self->orders_state.dest_blt_cy; + + if (xrdp_orders_send_delta(self, vals, 8)) { - out_uint16_le(self->out_s, x); + order_flags |= RDP_ORDER_DELTA; } - self->orders_state.dest_blt_x = x; - } - if (y != self->orders_state.dest_blt_y) - { - present |= 0x02; - if (order_flags & RDP_ORDER_DELTA) + + /* order_flags, set later, 1 byte */ + order_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if (order_flags & RDP_ORDER_CHANGE) { - out_uint8(self->out_s, y - self->orders_state.dest_blt_y); + out_uint8(self->out_s, self->orders_state.last_order); } - else + + present = 0; + /* present, set later, 1 byte */ + present_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) { - out_uint16_le(self->out_s, y); + xrdp_orders_out_bounds(self, rect); } - self->orders_state.dest_blt_y = y; - } - if (cx != self->orders_state.dest_blt_cx) - { - present |= 0x04; - if (order_flags & RDP_ORDER_DELTA) + + if (x != self->orders_state.dest_blt_x) { - out_uint8(self->out_s, cx - self->orders_state.dest_blt_cx); + present |= 0x01; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->orders_state.dest_blt_x); + } + else + { + out_uint16_le(self->out_s, x); + } + + self->orders_state.dest_blt_x = x; } - else + + if (y != self->orders_state.dest_blt_y) { - out_uint16_le(self->out_s, cx); + present |= 0x02; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->orders_state.dest_blt_y); + } + else + { + out_uint16_le(self->out_s, y); + } + + self->orders_state.dest_blt_y = y; } - self->orders_state.dest_blt_cx = cx; - } - if (cy != self->orders_state.dest_blt_cy) - { - present |= 0x08; - if (order_flags & RDP_ORDER_DELTA) + + if (cx != self->orders_state.dest_blt_cx) { - out_uint8(self->out_s, cy - self->orders_state.dest_blt_cy); + present |= 0x04; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->orders_state.dest_blt_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + + self->orders_state.dest_blt_cx = cx; } - else + + if (cy != self->orders_state.dest_blt_cy) { - out_uint16_le(self->out_s, cy); + present |= 0x08; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->orders_state.dest_blt_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + + self->orders_state.dest_blt_cy = cy; } - self->orders_state.dest_blt_cy = cy; - } - if (rop != self->orders_state.dest_blt_rop) - { - present |= 0x10; - out_uint8(self->out_s, rop); - self->orders_state.dest_blt_rop = rop; - } - xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, - present_ptr, present, 1); - return 0; + + if (rop != self->orders_state.dest_blt_rop) + { + present |= 0x10; + out_uint8(self->out_s, rop); + self->orders_state.dest_blt_rop = rop; + } + + xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, + present_ptr, present, 1); + return 0; } /*****************************************************************************/ @@ -1008,182 +1158,214 @@ xrdp_orders_dest_blt(struct xrdp_orders* self, int x, int y, /* send a line order */ /* max size 32 */ int APP_CC -xrdp_orders_line(struct xrdp_orders* self, int mix_mode, +xrdp_orders_line(struct xrdp_orders *self, int mix_mode, int startx, int starty, int endx, int endy, int rop, int bg_color, - struct xrdp_pen* pen, - struct xrdp_rect* rect) + struct xrdp_pen *pen, + struct xrdp_rect *rect) { - int order_flags = 0; - int vals[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - int present = 0; - char* present_ptr = (char *)NULL; - char* order_flags_ptr = (char *)NULL; - struct xrdp_pen blank_pen; + int order_flags = 0; + int vals[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int present = 0; + char *present_ptr = (char *)NULL; + char *order_flags_ptr = (char *)NULL; + struct xrdp_pen blank_pen; - g_memset(&blank_pen,0,sizeof(struct xrdp_pen)); - - /* if mix mode or rop are out of range, mstsc build 6000+ will parse the orders - wrong */ - if ((mix_mode < 1) || (mix_mode > 2)) /* TRANSPARENT(1) or OPAQUE(2) */ - { - mix_mode = 1; - } - if ((rop < 1) || (rop > 0x10)) - { - rop = 0x0d; /* R2_COPYPEN */ - } - xrdp_orders_check(self, 32); - self->order_count++; - order_flags = RDP_ORDER_STANDARD; - if (self->orders_state.last_order != RDP_ORDER_LINE) - { - order_flags |= RDP_ORDER_CHANGE; - } - self->orders_state.last_order = RDP_ORDER_LINE; - if (rect != 0) - { - /* if clip is present, still check if its needed */ - if (MIN(endx, startx) < rect->left || - MIN(endy, starty) < rect->top || - MAX(endx, startx) >= rect->right || - MAX(endy, starty) >= rect->bottom) - { - order_flags |= RDP_ORDER_BOUNDS; - if (xrdp_orders_last_bounds(self, rect)) - { - order_flags |= RDP_ORDER_LASTBOUNDS; - } - } - } - vals[0] = startx; - vals[1] = self->orders_state.line_startx; - vals[2] = starty; - vals[3] = self->orders_state.line_starty; - vals[4] = endx; - vals[5] = self->orders_state.line_endx; - vals[6] = endy; - vals[7] = self->orders_state.line_endy; - if (xrdp_orders_send_delta(self, vals, 8)) - { - order_flags |= RDP_ORDER_DELTA; - } - /* order_flags, set later, 1 byte */ - order_flags_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if (order_flags & RDP_ORDER_CHANGE) - { - out_uint8(self->out_s, self->orders_state.last_order); - } - present = 0; - /* present, set later, 2 bytes */ - present_ptr = self->out_s->p; - out_uint8s(self->out_s, 2); - if ((order_flags & RDP_ORDER_BOUNDS) && - !(order_flags & RDP_ORDER_LASTBOUNDS)) - { - xrdp_orders_out_bounds(self, rect); - } - if (mix_mode != self->orders_state.line_mix_mode) - { - present |= 0x0001; - out_uint16_le(self->out_s, mix_mode); - self->orders_state.line_mix_mode = mix_mode; - } - if (startx != self->orders_state.line_startx) - { - present |= 0x0002; - if (order_flags & RDP_ORDER_DELTA) - { - out_uint8(self->out_s, startx - self->orders_state.line_startx); - } - else - { - out_uint16_le(self->out_s, startx); - } - self->orders_state.line_startx = startx; - } - if (starty != self->orders_state.line_starty) - { - present |= 0x0004; - if (order_flags & RDP_ORDER_DELTA) - { - out_uint8(self->out_s, starty - self->orders_state.line_starty); - } - else - { - out_uint16_le(self->out_s, starty); - } - self->orders_state.line_starty = starty; - } - if (endx != self->orders_state.line_endx) - { - present |= 0x0008; - if (order_flags & RDP_ORDER_DELTA) - { - out_uint8(self->out_s, endx - self->orders_state.line_endx); - } - else - { - out_uint16_le(self->out_s, endx); - } - self->orders_state.line_endx = endx; - } - if (endy != self->orders_state.line_endy) - { - present |= 0x0010; - if (order_flags & RDP_ORDER_DELTA) - { - out_uint8(self->out_s, endy - self->orders_state.line_endy); - } - else - { - out_uint16_le(self->out_s, endy); - } - self->orders_state.line_endy = endy; - } - if (bg_color != self->orders_state.line_bg_color) - { - present |= 0x0020; - out_uint8(self->out_s, bg_color); - out_uint8(self->out_s, bg_color >> 8); - out_uint8(self->out_s, bg_color >> 16); - self->orders_state.line_bg_color = bg_color; - } - if (rop != self->orders_state.line_rop) - { - present |= 0x0040; - out_uint8(self->out_s, rop); - self->orders_state.line_rop = rop; - } - if (pen == 0) - { g_memset(&blank_pen, 0, sizeof(struct xrdp_pen)); - pen = &blank_pen; - } - if (pen->style != self->orders_state.line_pen.style) - { - present |= 0x0080; - out_uint8(self->out_s, pen->style); - self->orders_state.line_pen.style = pen->style; - } - if (pen->width != self->orders_state.line_pen.width) - { - present |= 0x0100; - out_uint8(self->out_s, pen->width); - self->orders_state.line_pen.width = pen->width; - } - if (pen->color != self->orders_state.line_pen.color) - { - present |= 0x0200; - out_uint8(self->out_s, pen->color); - out_uint8(self->out_s, pen->color >> 8); - out_uint8(self->out_s, pen->color >> 16); - self->orders_state.line_pen.color = pen->color; - } - xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, - present_ptr, present, 2); - return 0; + + /* if mix mode or rop are out of range, mstsc build 6000+ will parse the orders + wrong */ + if ((mix_mode < 1) || (mix_mode > 2)) /* TRANSPARENT(1) or OPAQUE(2) */ + { + mix_mode = 1; + } + + if ((rop < 1) || (rop > 0x10)) + { + rop = 0x0d; /* R2_COPYPEN */ + } + + xrdp_orders_check(self, 32); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + + if (self->orders_state.last_order != RDP_ORDER_LINE) + { + order_flags |= RDP_ORDER_CHANGE; + } + + self->orders_state.last_order = RDP_ORDER_LINE; + + if (rect != 0) + { + /* if clip is present, still check if its needed */ + if (MIN(endx, startx) < rect->left || + MIN(endy, starty) < rect->top || + MAX(endx, startx) >= rect->right || + MAX(endy, starty) >= rect->bottom) + { + order_flags |= RDP_ORDER_BOUNDS; + + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + } + + vals[0] = startx; + vals[1] = self->orders_state.line_startx; + vals[2] = starty; + vals[3] = self->orders_state.line_starty; + vals[4] = endx; + vals[5] = self->orders_state.line_endx; + vals[6] = endy; + vals[7] = self->orders_state.line_endy; + + if (xrdp_orders_send_delta(self, vals, 8)) + { + order_flags |= RDP_ORDER_DELTA; + } + + /* order_flags, set later, 1 byte */ + order_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->orders_state.last_order); + } + + present = 0; + /* present, set later, 2 bytes */ + present_ptr = self->out_s->p; + out_uint8s(self->out_s, 2); + + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + + if (mix_mode != self->orders_state.line_mix_mode) + { + present |= 0x0001; + out_uint16_le(self->out_s, mix_mode); + self->orders_state.line_mix_mode = mix_mode; + } + + if (startx != self->orders_state.line_startx) + { + present |= 0x0002; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, startx - self->orders_state.line_startx); + } + else + { + out_uint16_le(self->out_s, startx); + } + + self->orders_state.line_startx = startx; + } + + if (starty != self->orders_state.line_starty) + { + present |= 0x0004; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, starty - self->orders_state.line_starty); + } + else + { + out_uint16_le(self->out_s, starty); + } + + self->orders_state.line_starty = starty; + } + + if (endx != self->orders_state.line_endx) + { + present |= 0x0008; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, endx - self->orders_state.line_endx); + } + else + { + out_uint16_le(self->out_s, endx); + } + + self->orders_state.line_endx = endx; + } + + if (endy != self->orders_state.line_endy) + { + present |= 0x0010; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, endy - self->orders_state.line_endy); + } + else + { + out_uint16_le(self->out_s, endy); + } + + self->orders_state.line_endy = endy; + } + + if (bg_color != self->orders_state.line_bg_color) + { + present |= 0x0020; + out_uint8(self->out_s, bg_color); + out_uint8(self->out_s, bg_color >> 8); + out_uint8(self->out_s, bg_color >> 16); + self->orders_state.line_bg_color = bg_color; + } + + if (rop != self->orders_state.line_rop) + { + present |= 0x0040; + out_uint8(self->out_s, rop); + self->orders_state.line_rop = rop; + } + + if (pen == 0) + { + g_memset(&blank_pen, 0, sizeof(struct xrdp_pen)); + pen = &blank_pen; + } + + if (pen->style != self->orders_state.line_pen.style) + { + present |= 0x0080; + out_uint8(self->out_s, pen->style); + self->orders_state.line_pen.style = pen->style; + } + + if (pen->width != self->orders_state.line_pen.width) + { + present |= 0x0100; + out_uint8(self->out_s, pen->width); + self->orders_state.line_pen.width = pen->width; + } + + if (pen->color != self->orders_state.line_pen.color) + { + present |= 0x0200; + out_uint8(self->out_s, pen->color); + out_uint8(self->out_s, pen->color >> 8); + out_uint8(self->out_s, pen->color >> 16); + self->orders_state.line_pen.color = pen->color; + } + + xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, + present_ptr, present, 2); + return 0; } /*****************************************************************************/ @@ -1191,541 +1373,617 @@ xrdp_orders_line(struct xrdp_orders* self, int mix_mode, /* send a mem blt order */ /* max size 30 */ int APP_CC -xrdp_orders_mem_blt(struct xrdp_orders* self, int cache_id, +xrdp_orders_mem_blt(struct xrdp_orders *self, int cache_id, int color_table, int x, int y, int cx, int cy, int rop, int srcx, int srcy, - int cache_idx, struct xrdp_rect* rect) + int cache_idx, struct xrdp_rect *rect) { - int order_flags = 0; - int vals[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - int present = 0; - char* present_ptr = (char *)NULL; - char* order_flags_ptr = (char *)NULL; + int order_flags = 0; + int vals[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int present = 0; + char *present_ptr = (char *)NULL; + char *order_flags_ptr = (char *)NULL; - xrdp_orders_check(self, 30); - self->order_count++; - order_flags = RDP_ORDER_STANDARD; - if (self->orders_state.last_order != RDP_ORDER_MEMBLT) - { - order_flags |= RDP_ORDER_CHANGE; - } - self->orders_state.last_order = RDP_ORDER_MEMBLT; - if (rect != 0) - { - /* if clip is present, still check if its needed */ - if (x < rect->left || y < rect->top || - x + cx > rect->right || y + cy > rect->bottom) + xrdp_orders_check(self, 30); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + + if (self->orders_state.last_order != RDP_ORDER_MEMBLT) { - order_flags |= RDP_ORDER_BOUNDS; - if (xrdp_orders_last_bounds(self, rect)) - { - order_flags |= RDP_ORDER_LASTBOUNDS; - } + order_flags |= RDP_ORDER_CHANGE; } - } - vals[0] = x; - vals[1] = self->orders_state.mem_blt_x; - vals[2] = y; - vals[3] = self->orders_state.mem_blt_y; - vals[4] = cx; - vals[5] = self->orders_state.mem_blt_cx; - vals[6] = cy; - vals[7] = self->orders_state.mem_blt_cy; - vals[8] = srcx; - vals[9] = self->orders_state.mem_blt_srcx; - vals[10] = srcy; - vals[11] = self->orders_state.mem_blt_srcy; - if (xrdp_orders_send_delta(self, vals, 12)) - { - order_flags |= RDP_ORDER_DELTA; - } - /* order_flags, set later, 1 byte */ - order_flags_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if (order_flags & RDP_ORDER_CHANGE) - { - out_uint8(self->out_s, self->orders_state.last_order); - } - present = 0; - /* present, set later, 2 bytes */ - present_ptr = self->out_s->p; - out_uint8s(self->out_s, 2); - if ((order_flags & RDP_ORDER_BOUNDS) && - !(order_flags & RDP_ORDER_LASTBOUNDS)) - { - xrdp_orders_out_bounds(self, rect); - } - if (cache_id != self->orders_state.mem_blt_cache_id || - color_table != self->orders_state.mem_blt_color_table) - { - present |= 0x0001; - out_uint8(self->out_s, cache_id); - out_uint8(self->out_s, color_table); - self->orders_state.mem_blt_cache_id = cache_id; - self->orders_state.mem_blt_color_table = color_table; - } - if (x != self->orders_state.mem_blt_x) - { - present |= 0x0002; - if (order_flags & RDP_ORDER_DELTA) + + self->orders_state.last_order = RDP_ORDER_MEMBLT; + + if (rect != 0) { - out_uint8(self->out_s, x - self->orders_state.mem_blt_x); + /* if clip is present, still check if its needed */ + if (x < rect->left || y < rect->top || + x + cx > rect->right || y + cy > rect->bottom) + { + order_flags |= RDP_ORDER_BOUNDS; + + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } } - else + + vals[0] = x; + vals[1] = self->orders_state.mem_blt_x; + vals[2] = y; + vals[3] = self->orders_state.mem_blt_y; + vals[4] = cx; + vals[5] = self->orders_state.mem_blt_cx; + vals[6] = cy; + vals[7] = self->orders_state.mem_blt_cy; + vals[8] = srcx; + vals[9] = self->orders_state.mem_blt_srcx; + vals[10] = srcy; + vals[11] = self->orders_state.mem_blt_srcy; + + if (xrdp_orders_send_delta(self, vals, 12)) { - out_uint16_le(self->out_s, x); + order_flags |= RDP_ORDER_DELTA; } - self->orders_state.mem_blt_x = x; - } - if (y != self->orders_state.mem_blt_y) - { - present |= 0x0004; - if (order_flags & RDP_ORDER_DELTA) + + /* order_flags, set later, 1 byte */ + order_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if (order_flags & RDP_ORDER_CHANGE) { - out_uint8(self->out_s, y - self->orders_state.mem_blt_y); + out_uint8(self->out_s, self->orders_state.last_order); } - else + + present = 0; + /* present, set later, 2 bytes */ + present_ptr = self->out_s->p; + out_uint8s(self->out_s, 2); + + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) { - out_uint16_le(self->out_s, y); + xrdp_orders_out_bounds(self, rect); } - self->orders_state.mem_blt_y = y; - } - if (cx != self->orders_state.mem_blt_cx) - { - present |= 0x0008; - if (order_flags & RDP_ORDER_DELTA) + + if (cache_id != self->orders_state.mem_blt_cache_id || + color_table != self->orders_state.mem_blt_color_table) { - out_uint8(self->out_s, cx - self->orders_state.mem_blt_cx); + present |= 0x0001; + out_uint8(self->out_s, cache_id); + out_uint8(self->out_s, color_table); + self->orders_state.mem_blt_cache_id = cache_id; + self->orders_state.mem_blt_color_table = color_table; } - else + + if (x != self->orders_state.mem_blt_x) { - out_uint16_le(self->out_s, cx); + present |= 0x0002; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, x - self->orders_state.mem_blt_x); + } + else + { + out_uint16_le(self->out_s, x); + } + + self->orders_state.mem_blt_x = x; } - self->orders_state.mem_blt_cx = cx; - } - if (cy != self->orders_state.mem_blt_cy) - { - present |= 0x0010; - if (order_flags & RDP_ORDER_DELTA) + + if (y != self->orders_state.mem_blt_y) { - out_uint8(self->out_s, cy - self->orders_state.mem_blt_cy); + present |= 0x0004; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, y - self->orders_state.mem_blt_y); + } + else + { + out_uint16_le(self->out_s, y); + } + + self->orders_state.mem_blt_y = y; } - else + + if (cx != self->orders_state.mem_blt_cx) { - out_uint16_le(self->out_s, cy); + present |= 0x0008; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cx - self->orders_state.mem_blt_cx); + } + else + { + out_uint16_le(self->out_s, cx); + } + + self->orders_state.mem_blt_cx = cx; } - self->orders_state.mem_blt_cy = cy; - } - if (rop != self->orders_state.mem_blt_rop) - { - present |= 0x0020; - out_uint8(self->out_s, rop); - self->orders_state.mem_blt_rop = rop; - } - if (srcx != self->orders_state.mem_blt_srcx) - { - present |= 0x0040; - if (order_flags & RDP_ORDER_DELTA) + + if (cy != self->orders_state.mem_blt_cy) { - out_uint8(self->out_s, srcx - self->orders_state.mem_blt_srcx); + present |= 0x0010; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, cy - self->orders_state.mem_blt_cy); + } + else + { + out_uint16_le(self->out_s, cy); + } + + self->orders_state.mem_blt_cy = cy; } - else + + if (rop != self->orders_state.mem_blt_rop) { - out_uint16_le(self->out_s, srcx); + present |= 0x0020; + out_uint8(self->out_s, rop); + self->orders_state.mem_blt_rop = rop; } - self->orders_state.mem_blt_srcx = srcx; - } - if (srcy != self->orders_state.mem_blt_srcy) - { - present |= 0x0080; - if (order_flags & RDP_ORDER_DELTA) + + if (srcx != self->orders_state.mem_blt_srcx) { - out_uint8(self->out_s, srcy - self->orders_state.mem_blt_srcy); + present |= 0x0040; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcx - self->orders_state.mem_blt_srcx); + } + else + { + out_uint16_le(self->out_s, srcx); + } + + self->orders_state.mem_blt_srcx = srcx; } - else + + if (srcy != self->orders_state.mem_blt_srcy) { - out_uint16_le(self->out_s, srcy); + present |= 0x0080; + + if (order_flags & RDP_ORDER_DELTA) + { + out_uint8(self->out_s, srcy - self->orders_state.mem_blt_srcy); + } + else + { + out_uint16_le(self->out_s, srcy); + } + + self->orders_state.mem_blt_srcy = srcy; } - self->orders_state.mem_blt_srcy = srcy; - } - if (cache_idx != self->orders_state.mem_blt_cache_idx) - { - present |= 0x0100; - out_uint16_le(self->out_s, cache_idx); - self->orders_state.mem_blt_cache_idx = cache_idx; - } - xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, - present_ptr, present, 2); - return 0; + + if (cache_idx != self->orders_state.mem_blt_cache_idx) + { + present |= 0x0100; + out_uint16_le(self->out_s, cache_idx); + self->orders_state.mem_blt_cache_idx = cache_idx; + } + + xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, + present_ptr, present, 2); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_orders_text(struct xrdp_orders* self, +xrdp_orders_text(struct xrdp_orders *self, int font, int flags, int mixmode, int fg_color, int bg_color, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, - int x, int y, char* data, int data_len, - struct xrdp_rect* rect) + int x, int y, char *data, int data_len, + struct xrdp_rect *rect) { - int order_flags = 0; - int present = 0; - char* present_ptr = (char *)NULL; - char* order_flags_ptr = (char *)NULL; + int order_flags = 0; + int present = 0; + char *present_ptr = (char *)NULL; + char *order_flags_ptr = (char *)NULL; - xrdp_orders_check(self, 100); - self->order_count++; - order_flags = RDP_ORDER_STANDARD; - if (self->orders_state.last_order != RDP_ORDER_TEXT2) - { - order_flags |= RDP_ORDER_CHANGE; - } - self->orders_state.last_order = RDP_ORDER_TEXT2; - if (rect != 0) - { - /* if clip is present, still check if its needed */ - if ((box_right - box_left > 1 && - (box_left < rect->left || - box_top < rect->top || - box_right > rect->right || - box_bottom > rect->bottom)) || - (clip_left < rect->left || - clip_top < rect->top || - clip_right > rect->right || - clip_bottom > rect->bottom)) + xrdp_orders_check(self, 100); + self->order_count++; + order_flags = RDP_ORDER_STANDARD; + + if (self->orders_state.last_order != RDP_ORDER_TEXT2) { - order_flags |= RDP_ORDER_BOUNDS; - if (xrdp_orders_last_bounds(self, rect)) - { - order_flags |= RDP_ORDER_LASTBOUNDS; - } + order_flags |= RDP_ORDER_CHANGE; } - } - /* order_flags, set later, 1 byte */ - order_flags_ptr = self->out_s->p; - out_uint8s(self->out_s, 1); - if (order_flags & RDP_ORDER_CHANGE) - { - out_uint8(self->out_s, self->orders_state.last_order); - } - present = 0; - /* present, set later, 3 bytes */ - present_ptr = self->out_s->p; - out_uint8s(self->out_s, 3); - if ((order_flags & RDP_ORDER_BOUNDS) && - !(order_flags & RDP_ORDER_LASTBOUNDS)) - { - xrdp_orders_out_bounds(self, rect); - } - if (font != self->orders_state.text_font) - { - present |= 0x000001; - out_uint8(self->out_s, font); - self->orders_state.text_font = font; - } - if (flags != self->orders_state.text_flags) - { - present |= 0x000002; - out_uint8(self->out_s, flags); - self->orders_state.text_flags = flags; - } - /* unknown */ - if (mixmode != self->orders_state.text_mixmode) - { - present |= 0x000008; - out_uint8(self->out_s, mixmode); - self->orders_state.text_mixmode = mixmode; - } - if (fg_color != self->orders_state.text_fg_color) - { - present |= 0x000010; - out_uint8(self->out_s, fg_color); - out_uint8(self->out_s, fg_color >> 8); - out_uint8(self->out_s, fg_color >> 16); - self->orders_state.text_fg_color = fg_color; - } - if (bg_color != self->orders_state.text_bg_color) - { - present |= 0x000020; - out_uint8(self->out_s, bg_color); - out_uint8(self->out_s, bg_color >> 8); - out_uint8(self->out_s, bg_color >> 16); - self->orders_state.text_bg_color = bg_color; - } - if (clip_left != self->orders_state.text_clip_left) - { - present |= 0x000040; - out_uint16_le(self->out_s, clip_left); - self->orders_state.text_clip_left = clip_left; - } - if (clip_top != self->orders_state.text_clip_top) - { - present |= 0x000080; - out_uint16_le(self->out_s, clip_top); - self->orders_state.text_clip_top = clip_top; - } - if (clip_right != self->orders_state.text_clip_right) - { - present |= 0x000100; - out_uint16_le(self->out_s, clip_right); - self->orders_state.text_clip_right = clip_right; - } - if (clip_bottom != self->orders_state.text_clip_bottom) - { - present |= 0x000200; - out_uint16_le(self->out_s, clip_bottom); - self->orders_state.text_clip_bottom = clip_bottom; - } - if (box_left != self->orders_state.text_box_left) - { - present |= 0x000400; - out_uint16_le(self->out_s, box_left); - self->orders_state.text_box_left = box_left; - } - if (box_top != self->orders_state.text_box_top) - { - present |= 0x000800; - out_uint16_le(self->out_s, box_top); - self->orders_state.text_box_top = box_top; - } - if (box_right != self->orders_state.text_box_right) - { - present |= 0x001000; - out_uint16_le(self->out_s, box_right); - self->orders_state.text_box_right = box_right; - } - if (box_bottom != self->orders_state.text_box_bottom) - { - present |= 0x002000; - out_uint16_le(self->out_s, box_bottom); - self->orders_state.text_box_bottom = box_bottom; - } - if (x != self->orders_state.text_x) - { - present |= 0x080000; - out_uint16_le(self->out_s, x); - self->orders_state.text_x = x; - } - if (y != self->orders_state.text_y) - { - present |= 0x100000; - out_uint16_le(self->out_s, y); - self->orders_state.text_y = y; - } - { - /* always send text */ - present |= 0x200000; - out_uint8(self->out_s, data_len); - out_uint8a(self->out_s, data, data_len); - } - xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, - present_ptr, present, 3); - return 0; + + self->orders_state.last_order = RDP_ORDER_TEXT2; + + if (rect != 0) + { + /* if clip is present, still check if its needed */ + if ((box_right - box_left > 1 && + (box_left < rect->left || + box_top < rect->top || + box_right > rect->right || + box_bottom > rect->bottom)) || + (clip_left < rect->left || + clip_top < rect->top || + clip_right > rect->right || + clip_bottom > rect->bottom)) + { + order_flags |= RDP_ORDER_BOUNDS; + + if (xrdp_orders_last_bounds(self, rect)) + { + order_flags |= RDP_ORDER_LASTBOUNDS; + } + } + } + + /* order_flags, set later, 1 byte */ + order_flags_ptr = self->out_s->p; + out_uint8s(self->out_s, 1); + + if (order_flags & RDP_ORDER_CHANGE) + { + out_uint8(self->out_s, self->orders_state.last_order); + } + + present = 0; + /* present, set later, 3 bytes */ + present_ptr = self->out_s->p; + out_uint8s(self->out_s, 3); + + if ((order_flags & RDP_ORDER_BOUNDS) && + !(order_flags & RDP_ORDER_LASTBOUNDS)) + { + xrdp_orders_out_bounds(self, rect); + } + + if (font != self->orders_state.text_font) + { + present |= 0x000001; + out_uint8(self->out_s, font); + self->orders_state.text_font = font; + } + + if (flags != self->orders_state.text_flags) + { + present |= 0x000002; + out_uint8(self->out_s, flags); + self->orders_state.text_flags = flags; + } + + /* unknown */ + if (mixmode != self->orders_state.text_mixmode) + { + present |= 0x000008; + out_uint8(self->out_s, mixmode); + self->orders_state.text_mixmode = mixmode; + } + + if (fg_color != self->orders_state.text_fg_color) + { + present |= 0x000010; + out_uint8(self->out_s, fg_color); + out_uint8(self->out_s, fg_color >> 8); + out_uint8(self->out_s, fg_color >> 16); + self->orders_state.text_fg_color = fg_color; + } + + if (bg_color != self->orders_state.text_bg_color) + { + present |= 0x000020; + out_uint8(self->out_s, bg_color); + out_uint8(self->out_s, bg_color >> 8); + out_uint8(self->out_s, bg_color >> 16); + self->orders_state.text_bg_color = bg_color; + } + + if (clip_left != self->orders_state.text_clip_left) + { + present |= 0x000040; + out_uint16_le(self->out_s, clip_left); + self->orders_state.text_clip_left = clip_left; + } + + if (clip_top != self->orders_state.text_clip_top) + { + present |= 0x000080; + out_uint16_le(self->out_s, clip_top); + self->orders_state.text_clip_top = clip_top; + } + + if (clip_right != self->orders_state.text_clip_right) + { + present |= 0x000100; + out_uint16_le(self->out_s, clip_right); + self->orders_state.text_clip_right = clip_right; + } + + if (clip_bottom != self->orders_state.text_clip_bottom) + { + present |= 0x000200; + out_uint16_le(self->out_s, clip_bottom); + self->orders_state.text_clip_bottom = clip_bottom; + } + + if (box_left != self->orders_state.text_box_left) + { + present |= 0x000400; + out_uint16_le(self->out_s, box_left); + self->orders_state.text_box_left = box_left; + } + + if (box_top != self->orders_state.text_box_top) + { + present |= 0x000800; + out_uint16_le(self->out_s, box_top); + self->orders_state.text_box_top = box_top; + } + + if (box_right != self->orders_state.text_box_right) + { + present |= 0x001000; + out_uint16_le(self->out_s, box_right); + self->orders_state.text_box_right = box_right; + } + + if (box_bottom != self->orders_state.text_box_bottom) + { + present |= 0x002000; + out_uint16_le(self->out_s, box_bottom); + self->orders_state.text_box_bottom = box_bottom; + } + + if (x != self->orders_state.text_x) + { + present |= 0x080000; + out_uint16_le(self->out_s, x); + self->orders_state.text_x = x; + } + + if (y != self->orders_state.text_y) + { + present |= 0x100000; + out_uint16_le(self->out_s, y); + self->orders_state.text_y = y; + } + + { + /* always send text */ + present |= 0x200000; + out_uint8(self->out_s, data_len); + out_uint8a(self->out_s, data, data_len); + } + + xrdp_order_pack_small_or_tiny(self, order_flags_ptr, order_flags, + present_ptr, present, 3); + return 0; } /*****************************************************************************/ /* returns error */ /* when a palette gets sent, send the main palette too */ int APP_CC -xrdp_orders_send_palette(struct xrdp_orders* self, int* palette, +xrdp_orders_send_palette(struct xrdp_orders *self, int *palette, int cache_id) { - int order_flags; - int len; - int i; + int order_flags; + int len; + int i; - xrdp_orders_check(self, 2000); - self->order_count++; - order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; - out_uint8(self->out_s, order_flags); - len = 1027 - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - out_uint16_le(self->out_s, 0); /* flags */ - out_uint8(self->out_s, RDP_ORDER_COLCACHE); /* type */ - out_uint8(self->out_s, cache_id); - out_uint16_le(self->out_s, 256); /* num colors */ - for (i = 0; i < 256; i++) - { - out_uint8(self->out_s, palette[i]); - out_uint8(self->out_s, palette[i] >> 8); - out_uint8(self->out_s, palette[i] >> 16); - out_uint8(self->out_s, 0); - } - return 0; + xrdp_orders_check(self, 2000); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = 1027 - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 0); /* flags */ + out_uint8(self->out_s, RDP_ORDER_COLCACHE); /* type */ + out_uint8(self->out_s, cache_id); + out_uint16_le(self->out_s, 256); /* num colors */ + + for (i = 0; i < 256; i++) + { + out_uint8(self->out_s, palette[i]); + out_uint8(self->out_s, palette[i] >> 8); + out_uint8(self->out_s, palette[i] >> 16); + out_uint8(self->out_s, 0); + } + + return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 16 */ int APP_CC -xrdp_orders_send_raw_bitmap(struct xrdp_orders* self, - int width, int height, int bpp, char* data, +xrdp_orders_send_raw_bitmap(struct xrdp_orders *self, + int width, int height, int bpp, char *data, int cache_id, int cache_idx) { - int order_flags = 0; - int len = 0; - int bufsize = 0; - int Bpp = 0; - int i = 0; - int j = 0; - int pixel = 0; - int e = 0; + int order_flags = 0; + int len = 0; + int bufsize = 0; + int Bpp = 0; + int i = 0; + int j = 0; + int pixel = 0; + int e = 0; - if (width > 64) - { - g_writeln("error, width > 64"); - return 1; - } - if (height > 64) - { - g_writeln("error, height > 64"); - return 1; - } - e = width % 4; - if (e != 0) - { - e = 4 - e; - } - Bpp = (bpp + 7) / 8; - bufsize = (width + e) * height * Bpp; - xrdp_orders_check(self, bufsize + 16); - self->order_count++; - order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; - out_uint8(self->out_s, order_flags); - len = (bufsize + 9) - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - out_uint16_le(self->out_s, 8); /* flags */ - out_uint8(self->out_s, RDP_ORDER_RAW_BMPCACHE); /* type */ - out_uint8(self->out_s, cache_id); - out_uint8s(self->out_s, 1); /* pad */ - out_uint8(self->out_s, width + e); - out_uint8(self->out_s, height); - out_uint8(self->out_s, bpp); - out_uint16_le(self->out_s, bufsize); - out_uint16_le(self->out_s, cache_idx); - for (i = height - 1; i >= 0; i--) - { - for (j = 0; j < width; j++) + if (width > 64) { - if (Bpp == 3) - { - pixel = GETPIXEL32(data, j, i, width); - out_uint8(self->out_s, pixel >> 16); - out_uint8(self->out_s, pixel >> 8); - out_uint8(self->out_s, pixel); - } - else if (Bpp == 2) - { - pixel = GETPIXEL16(data, j, i, width); - out_uint8(self->out_s, pixel); - out_uint8(self->out_s, pixel >> 8); - } - else if (Bpp == 1) - { - pixel = GETPIXEL8(data, j, i, width); - out_uint8(self->out_s, pixel); - } + g_writeln("error, width > 64"); + return 1; } - for (j = 0; j < e; j++) + + if (height > 64) { - out_uint8s(self->out_s, Bpp); + g_writeln("error, height > 64"); + return 1; } - } - return 0; + + e = width % 4; + + if (e != 0) + { + e = 4 - e; + } + + Bpp = (bpp + 7) / 8; + bufsize = (width + e) * height * Bpp; + xrdp_orders_check(self, bufsize + 16); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (bufsize + 9) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 8); /* flags */ + out_uint8(self->out_s, RDP_ORDER_RAW_BMPCACHE); /* type */ + out_uint8(self->out_s, cache_id); + out_uint8s(self->out_s, 1); /* pad */ + out_uint8(self->out_s, width + e); + out_uint8(self->out_s, height); + out_uint8(self->out_s, bpp); + out_uint16_le(self->out_s, bufsize); + out_uint16_le(self->out_s, cache_idx); + + for (i = height - 1; i >= 0; i--) + { + for (j = 0; j < width; j++) + { + if (Bpp == 3) + { + pixel = GETPIXEL32(data, j, i, width); + out_uint8(self->out_s, pixel >> 16); + out_uint8(self->out_s, pixel >> 8); + out_uint8(self->out_s, pixel); + } + else if (Bpp == 2) + { + pixel = GETPIXEL16(data, j, i, width); + out_uint8(self->out_s, pixel); + out_uint8(self->out_s, pixel >> 8); + } + else if (Bpp == 1) + { + pixel = GETPIXEL8(data, j, i, width); + out_uint8(self->out_s, pixel); + } + } + + for (j = 0; j < e; j++) + { + out_uint8s(self->out_s, Bpp); + } + } + + return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 16 */ int APP_CC -xrdp_orders_send_bitmap(struct xrdp_orders* self, - int width, int height, int bpp, char* data, +xrdp_orders_send_bitmap(struct xrdp_orders *self, + int width, int height, int bpp, char *data, int cache_id, int cache_idx) { - int order_flags = 0; - int len = 0; - int bufsize = 0; - int Bpp = 0; - int i = 0; - int lines_sending = 0; - int e = 0; - struct stream* s = NULL; - struct stream* temp_s = NULL; - char* p = NULL; + int order_flags = 0; + int len = 0; + int bufsize = 0; + int Bpp = 0; + int i = 0; + int lines_sending = 0; + int e = 0; + struct stream *s = NULL; + struct stream *temp_s = NULL; + char *p = NULL; - if (width > 64) - { - g_writeln("error, width > 64"); - return 1; - } - if (height > 64) - { - g_writeln("error, height > 64"); - return 1; - } - e = width % 4; - if (e != 0) - { - e = 4 - e; - } - make_stream(s); - init_stream(s, 16384); - make_stream(temp_s); - init_stream(temp_s, 16384); - p = s->p; - i = height; - lines_sending = xrdp_bitmap_compress(data, width, height, s, bpp, 16384, - i - 1, temp_s, e); - if (lines_sending != height) - { + if (width > 64) + { + g_writeln("error, width > 64"); + return 1; + } + + if (height > 64) + { + g_writeln("error, height > 64"); + return 1; + } + + e = width % 4; + + if (e != 0) + { + e = 4 - e; + } + + make_stream(s); + init_stream(s, 16384); + make_stream(temp_s); + init_stream(temp_s, 16384); + p = s->p; + i = height; + lines_sending = xrdp_bitmap_compress(data, width, height, s, bpp, 16384, + i - 1, temp_s, e); + + if (lines_sending != height) + { + free_stream(s); + free_stream(temp_s); + g_writeln("error in xrdp_orders_send_bitmap, lines_sending(%d) != \ +height(%d)", lines_sending, height); + return 1; + } + + bufsize = (int)(s->p - p); + Bpp = (bpp + 7) / 8; + xrdp_orders_check(self, bufsize + 16); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + + if (self->rdp_layer->client_info.op2) + { + len = (bufsize + 9) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 1024); /* flags */ + } + else + { + len = (bufsize + 9 + 8) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 8); /* flags */ + } + + out_uint8(self->out_s, RDP_ORDER_BMPCACHE); /* type */ + out_uint8(self->out_s, cache_id); + out_uint8s(self->out_s, 1); /* pad */ + out_uint8(self->out_s, width + e); + out_uint8(self->out_s, height); + out_uint8(self->out_s, bpp); + out_uint16_le(self->out_s, bufsize/* + 8*/); + out_uint16_le(self->out_s, cache_idx); + + if (!self->rdp_layer->client_info.op2) + { + out_uint8s(self->out_s, 2); /* pad */ + out_uint16_le(self->out_s, bufsize); + out_uint16_le(self->out_s, (width + e) * Bpp); /* line size */ + out_uint16_le(self->out_s, (width + e) * + Bpp * height); /* final size */ + } + + out_uint8a(self->out_s, s->data, bufsize); free_stream(s); free_stream(temp_s); - g_writeln("error in xrdp_orders_send_bitmap, lines_sending(%d) != \ -height(%d)", lines_sending, height); - return 1; - } - bufsize = (int)(s->p - p); - Bpp = (bpp + 7) / 8; - xrdp_orders_check(self, bufsize + 16); - self->order_count++; - order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; - out_uint8(self->out_s, order_flags); - if (self->rdp_layer->client_info.op2) - { - len = (bufsize + 9) - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - out_uint16_le(self->out_s, 1024); /* flags */ - } - else - { - len = (bufsize + 9 + 8) - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - out_uint16_le(self->out_s, 8); /* flags */ - } - out_uint8(self->out_s, RDP_ORDER_BMPCACHE); /* type */ - out_uint8(self->out_s, cache_id); - out_uint8s(self->out_s, 1); /* pad */ - out_uint8(self->out_s, width + e); - out_uint8(self->out_s, height); - out_uint8(self->out_s, bpp); - out_uint16_le(self->out_s, bufsize/* + 8*/); - out_uint16_le(self->out_s, cache_idx); - if (!self->rdp_layer->client_info.op2) - { - out_uint8s(self->out_s, 2); /* pad */ - out_uint16_le(self->out_s, bufsize); - out_uint16_le(self->out_s, (width + e) * Bpp); /* line size */ - out_uint16_le(self->out_s, (width + e) * - Bpp * height); /* final size */ - } - out_uint8a(self->out_s, s->data, bufsize); - free_stream(s); - free_stream(temp_s); - return 0; + return 0; } /*****************************************************************************/ @@ -1733,457 +1991,492 @@ height(%d)", lines_sending, height); /* max size datasize + 18*/ /* todo, only sends one for now */ int APP_CC -xrdp_orders_send_font(struct xrdp_orders* self, - struct xrdp_font_char* font_char, +xrdp_orders_send_font(struct xrdp_orders *self, + struct xrdp_font_char *font_char, int font_index, int char_index) { - int order_flags = 0; - int datasize = 0; - int len = 0; + int order_flags = 0; + int datasize = 0; + int len = 0; - datasize = FONT_DATASIZE(font_char); - xrdp_orders_check(self, datasize + 18); - self->order_count++; - order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; - out_uint8(self->out_s, order_flags); - len = (datasize + 12) - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - out_uint16_le(self->out_s, 8); /* flags */ - out_uint8(self->out_s, RDP_ORDER_FONTCACHE); /* type */ - out_uint8(self->out_s, font_index); - out_uint8(self->out_s, 1); /* num of chars */ - out_uint16_le(self->out_s, char_index); - out_uint16_le(self->out_s, font_char->offset); - out_uint16_le(self->out_s, font_char->baseline); - out_uint16_le(self->out_s, font_char->width); - out_uint16_le(self->out_s, font_char->height); - out_uint8a(self->out_s, font_char->data, datasize); - return 0; + datasize = FONT_DATASIZE(font_char); + xrdp_orders_check(self, datasize + 18); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (datasize + 12) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 8); /* flags */ + out_uint8(self->out_s, RDP_ORDER_FONTCACHE); /* type */ + out_uint8(self->out_s, font_index); + out_uint8(self->out_s, 1); /* num of chars */ + out_uint16_le(self->out_s, char_index); + out_uint16_le(self->out_s, font_char->offset); + out_uint16_le(self->out_s, font_char->baseline); + out_uint16_le(self->out_s, font_char->width); + out_uint16_le(self->out_s, font_char->height); + out_uint8a(self->out_s, font_char->data, datasize); + return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 14 */ int APP_CC -xrdp_orders_send_raw_bitmap2(struct xrdp_orders* self, - int width, int height, int bpp, char* data, +xrdp_orders_send_raw_bitmap2(struct xrdp_orders *self, + int width, int height, int bpp, char *data, int cache_id, int cache_idx) { - int order_flags = 0; - int len = 0; - int bufsize = 0; - int Bpp = 0; - int i = 0; - int j = 0; - int pixel = 0; - int e = 0; + int order_flags = 0; + int len = 0; + int bufsize = 0; + int Bpp = 0; + int i = 0; + int j = 0; + int pixel = 0; + int e = 0; - if (width > 64) - { - g_writeln("error, width > 64"); - return 1; - } - if (height > 64) - { - g_writeln("error, height > 64"); - return 1; - } - e = width % 4; - if (e != 0) - { - e = 4 - e; - } - Bpp = (bpp + 7) / 8; - bufsize = (width + e) * height * Bpp; - xrdp_orders_check(self, bufsize + 14); - self->order_count++; - order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; - out_uint8(self->out_s, order_flags); - len = (bufsize + 6) - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - i = (((Bpp + 2) << 3) & 0x38) | (cache_id & 7); - out_uint16_le(self->out_s, i); /* flags */ - out_uint8(self->out_s, RDP_ORDER_RAW_BMPCACHE2); /* type */ - out_uint8(self->out_s, width + e); - out_uint8(self->out_s, height); - out_uint16_be(self->out_s, bufsize | 0x4000); - i = ((cache_idx >> 8) & 0xff) | 0x80; - out_uint8(self->out_s, i); - i = cache_idx & 0xff; - out_uint8(self->out_s, i); - for (i = height - 1; i >= 0; i--) - { - for (j = 0; j < width; j++) + if (width > 64) { - if (Bpp == 3) - { - pixel = GETPIXEL32(data, j, i, width); - out_uint8(self->out_s, pixel >> 16); - out_uint8(self->out_s, pixel >> 8); - out_uint8(self->out_s, pixel); - } - else if (Bpp == 2) - { - pixel = GETPIXEL16(data, j, i, width); - out_uint8(self->out_s, pixel); - out_uint8(self->out_s, pixel >> 8); - } - else if (Bpp == 1) - { - pixel = GETPIXEL8(data, j, i, width); - out_uint8(self->out_s, pixel); - } + g_writeln("error, width > 64"); + return 1; } - for (j = 0; j < e; j++) + + if (height > 64) { - out_uint8s(self->out_s, Bpp); + g_writeln("error, height > 64"); + return 1; } - } - return 0; + + e = width % 4; + + if (e != 0) + { + e = 4 - e; + } + + Bpp = (bpp + 7) / 8; + bufsize = (width + e) * height * Bpp; + xrdp_orders_check(self, bufsize + 14); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (bufsize + 6) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + i = (((Bpp + 2) << 3) & 0x38) | (cache_id & 7); + out_uint16_le(self->out_s, i); /* flags */ + out_uint8(self->out_s, RDP_ORDER_RAW_BMPCACHE2); /* type */ + out_uint8(self->out_s, width + e); + out_uint8(self->out_s, height); + out_uint16_be(self->out_s, bufsize | 0x4000); + i = ((cache_idx >> 8) & 0xff) | 0x80; + out_uint8(self->out_s, i); + i = cache_idx & 0xff; + out_uint8(self->out_s, i); + + for (i = height - 1; i >= 0; i--) + { + for (j = 0; j < width; j++) + { + if (Bpp == 3) + { + pixel = GETPIXEL32(data, j, i, width); + out_uint8(self->out_s, pixel >> 16); + out_uint8(self->out_s, pixel >> 8); + out_uint8(self->out_s, pixel); + } + else if (Bpp == 2) + { + pixel = GETPIXEL16(data, j, i, width); + out_uint8(self->out_s, pixel); + out_uint8(self->out_s, pixel >> 8); + } + else if (Bpp == 1) + { + pixel = GETPIXEL8(data, j, i, width); + out_uint8(self->out_s, pixel); + } + } + + for (j = 0; j < e; j++) + { + out_uint8s(self->out_s, Bpp); + } + } + + return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 14 */ int APP_CC -xrdp_orders_send_bitmap2(struct xrdp_orders* self, - int width, int height, int bpp, char* data, +xrdp_orders_send_bitmap2(struct xrdp_orders *self, + int width, int height, int bpp, char *data, int cache_id, int cache_idx, int hints) { - int order_flags = 0; - int len = 0; - int bufsize = 0; - int Bpp = 0; - int i = 0; - int lines_sending = 0; - int e = 0; - struct stream* s = NULL; - struct stream* temp_s = NULL; - char* p = NULL; + int order_flags = 0; + int len = 0; + int bufsize = 0; + int Bpp = 0; + int i = 0; + int lines_sending = 0; + int e = 0; + struct stream *s = NULL; + struct stream *temp_s = NULL; + char *p = NULL; - if (width > 64) - { - g_writeln("error, width > 64"); - return 1; - } - if (height > 64) - { - g_writeln("error, height > 64"); - return 1; - } - e = width % 4; - if (e != 0) - { - e = 4 - e; - } - make_stream(s); - init_stream(s, 16384); - make_stream(temp_s); - init_stream(temp_s, 16384); - p = s->p; - i = height; - lines_sending = xrdp_bitmap_compress(data, width, height, s, bpp, 16384, + if (width > 64) + { + g_writeln("error, width > 64"); + return 1; + } + + if (height > 64) + { + g_writeln("error, height > 64"); + return 1; + } + + e = width % 4; + + if (e != 0) + { + e = 4 - e; + } + + make_stream(s); + init_stream(s, 16384); + make_stream(temp_s); + init_stream(temp_s, 16384); + p = s->p; + i = height; + lines_sending = xrdp_bitmap_compress(data, width, height, s, bpp, 16384, i - 1, temp_s, e); - if (lines_sending != height) - { + + if (lines_sending != height) + { + free_stream(s); + free_stream(temp_s); + g_writeln("error in xrdp_orders_send_bitmap2, lines_sending(%d) != \ +height(%d)", lines_sending, height); + return 1; + } + + bufsize = (int)(s->p - p); + Bpp = (bpp + 7) / 8; + xrdp_orders_check(self, bufsize + 14); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (bufsize + 6) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + i = (((Bpp + 2) << 3) & 0x38) | (cache_id & 7); + i = i | (0x08 << 7); /* CBR2_NO_BITMAP_COMPRESSION_HDR */ + out_uint16_le(self->out_s, i); /* flags */ + out_uint8(self->out_s, RDP_ORDER_BMPCACHE2); /* type */ + out_uint8(self->out_s, width + e); + out_uint8(self->out_s, height); + out_uint16_be(self->out_s, bufsize | 0x4000); + i = ((cache_idx >> 8) & 0xff) | 0x80; + out_uint8(self->out_s, i); + i = cache_idx & 0xff; + out_uint8(self->out_s, i); + out_uint8a(self->out_s, s->data, bufsize); free_stream(s); free_stream(temp_s); - g_writeln("error in xrdp_orders_send_bitmap2, lines_sending(%d) != \ -height(%d)", lines_sending, height); - return 1; - } - bufsize = (int)(s->p - p); - Bpp = (bpp + 7) / 8; - xrdp_orders_check(self, bufsize + 14); - self->order_count++; - order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; - out_uint8(self->out_s, order_flags); - len = (bufsize + 6) - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - i = (((Bpp + 2) << 3) & 0x38) | (cache_id & 7); - i = i | (0x08 << 7); /* CBR2_NO_BITMAP_COMPRESSION_HDR */ - out_uint16_le(self->out_s, i); /* flags */ - out_uint8(self->out_s, RDP_ORDER_BMPCACHE2); /* type */ - out_uint8(self->out_s, width + e); - out_uint8(self->out_s, height); - out_uint16_be(self->out_s, bufsize | 0x4000); - i = ((cache_idx >> 8) & 0xff) | 0x80; - out_uint8(self->out_s, i); - i = cache_idx & 0xff; - out_uint8(self->out_s, i); - out_uint8a(self->out_s, s->data, bufsize); - free_stream(s); - free_stream(temp_s); - return 0; + return 0; } /*****************************************************************************/ static int -xrdp_orders_send_as_jpeg(struct xrdp_orders* self, +xrdp_orders_send_as_jpeg(struct xrdp_orders *self, int width, int height, int bpp, int hints) { - if (hints & 1) - { - return 0; - } - if (bpp != 24) - { - return 0; - } - if (width * height < 64) - { - return 0; - } - return 1; + if (hints & 1) + { + return 0; + } + + if (bpp != 24) + { + return 0; + } + + if (width * height < 64) + { + return 0; + } + + return 1; } #if defined(XRDP_FREERDP1) /*****************************************************************************/ /* secondary drawing order (bitmap v3) using remotefx compression */ static int APP_CC -xrdp_orders_send_as_rfx(struct xrdp_orders* self, +xrdp_orders_send_as_rfx(struct xrdp_orders *self, int width, int height, int bpp, int hints) { - if (hints & 1) - { - return 0; - } - if (bpp != 24) - { - return 0; - } - if (width * height < 64) - { - return 0; - } - return 1; + if (hints & 1) + { + return 0; + } + + if (bpp != 24) + { + return 0; + } + + if (width * height < 64) + { + return 0; + } + + return 1; } #endif /*****************************************************************************/ static int APP_CC -xrdp_orders_out_v3(struct xrdp_orders* self, int cache_id, int cache_idx, - char* buf, int bufsize, int width, int height, int bpp, +xrdp_orders_out_v3(struct xrdp_orders *self, int cache_id, int cache_idx, + char *buf, int bufsize, int width, int height, int bpp, int codec_id) { - int Bpp; - int order_flags; - int len; - int i; + int Bpp; + int order_flags; + int len; + int i; - Bpp = (bpp + 7) / 8; - xrdp_orders_check(self, bufsize + 30); - self->order_count++; - order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; - out_uint8(self->out_s, order_flags); - len = (bufsize + 22) - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - i = (((Bpp + 2) << 3) & 0x38) | (cache_id & 7); - out_uint16_le(self->out_s, i); /* flags */ - out_uint8(self->out_s, RDP_ORDER_BMPCACHE3); /* type */ - /* cache index */ - out_uint16_le(self->out_s, cache_idx); - /* persistant cache key 1/2 */ - out_uint32_le(self->out_s, 0); - out_uint32_le(self->out_s, 0); - /* bitmap data */ - out_uint8(self->out_s, bpp); - out_uint8(self->out_s, 0); /* reserved */ - out_uint8(self->out_s, 0); /* reserved */ - out_uint8(self->out_s, codec_id); - out_uint16_le(self->out_s, width); - out_uint16_le(self->out_s, height); - out_uint32_le(self->out_s, bufsize); - out_uint8a(self->out_s, buf, bufsize); - return 0; + Bpp = (bpp + 7) / 8; + xrdp_orders_check(self, bufsize + 30); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (bufsize + 22) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + i = (((Bpp + 2) << 3) & 0x38) | (cache_id & 7); + out_uint16_le(self->out_s, i); /* flags */ + out_uint8(self->out_s, RDP_ORDER_BMPCACHE3); /* type */ + /* cache index */ + out_uint16_le(self->out_s, cache_idx); + /* persistant cache key 1/2 */ + out_uint32_le(self->out_s, 0); + out_uint32_le(self->out_s, 0); + /* bitmap data */ + out_uint8(self->out_s, bpp); + out_uint8(self->out_s, 0); /* reserved */ + out_uint8(self->out_s, 0); /* reserved */ + out_uint8(self->out_s, codec_id); + out_uint16_le(self->out_s, width); + out_uint16_le(self->out_s, height); + out_uint32_le(self->out_s, bufsize); + out_uint8a(self->out_s, buf, bufsize); + return 0; } /*****************************************************************************/ /* secondary drawing order (bitmap v3) using remotefx compression */ int APP_CC -xrdp_orders_send_bitmap3(struct xrdp_orders* self, - int width, int height, int bpp, char* data, +xrdp_orders_send_bitmap3(struct xrdp_orders *self, + int width, int height, int bpp, char *data, int cache_id, int cache_idx, int hints) { - int e; - int bufsize; - int quality; - struct stream* xr_s; /* xrdp stream */ - struct stream* temp_s; /* xrdp stream */ - struct xrdp_client_info* ci; + int e; + int bufsize; + int quality; + struct stream *xr_s; /* xrdp stream */ + struct stream *temp_s; /* xrdp stream */ + struct xrdp_client_info *ci; #if defined(XRDP_FREERDP1) - STREAM* fr_s; /* FreeRDP stream */ - RFX_CONTEXT* context; - RFX_RECT rect; + STREAM *fr_s; /* FreeRDP stream */ + RFX_CONTEXT *context; + RFX_RECT rect; #endif - ci = &(self->rdp_layer->client_info); - if (ci->v3_codec_id == 0) - { - return 2; - } - if (ci->v3_codec_id == ci->rfx_codec_id) - { + ci = &(self->rdp_layer->client_info); + + if (ci->v3_codec_id == 0) + { + return 2; + } + + if (ci->v3_codec_id == ci->rfx_codec_id) + { #if defined(XRDP_FREERDP1) - if (!xrdp_orders_send_as_rfx(self, width, height, bpp, hints)) - { - return 2; - } - LLOGLN(10, ("xrdp_orders_send_bitmap3: rfx")); - context = (RFX_CONTEXT*)(self->rdp_layer->rfx_enc); - make_stream(xr_s); - init_stream(xr_s, 16384); - fr_s = stream_new(0); - stream_attach(fr_s, (tui8*)(xr_s->data), 16384); - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - rfx_compose_message(context, fr_s, &rect, 1, (tui8*)data, width, - height, width * 4); - bufsize = stream_get_length(fr_s); - xrdp_orders_out_v3(self, cache_id, cache_idx, (char*)(fr_s->data), bufsize, - width, height, bpp,ci->v3_codec_id); - stream_detach(fr_s); - stream_free(fr_s); - free_stream(xr_s); - return 0; + + if (!xrdp_orders_send_as_rfx(self, width, height, bpp, hints)) + { + return 2; + } + + LLOGLN(10, ("xrdp_orders_send_bitmap3: rfx")); + context = (RFX_CONTEXT *)(self->rdp_layer->rfx_enc); + make_stream(xr_s); + init_stream(xr_s, 16384); + fr_s = stream_new(0); + stream_attach(fr_s, (tui8 *)(xr_s->data), 16384); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + rfx_compose_message(context, fr_s, &rect, 1, (tui8 *)data, width, + height, width * 4); + bufsize = stream_get_length(fr_s); + xrdp_orders_out_v3(self, cache_id, cache_idx, (char *)(fr_s->data), bufsize, + width, height, bpp, ci->v3_codec_id); + stream_detach(fr_s); + stream_free(fr_s); + free_stream(xr_s); + return 0; #else - return 2; + return 2; #endif - } - else if (ci->v3_codec_id == ci->jpeg_codec_id) - { + } + else if (ci->v3_codec_id == ci->jpeg_codec_id) + { #if defined(XRDP_JPEG) - if (!xrdp_orders_send_as_jpeg(self, width, height, bpp, hints)) - { - LLOGLN(10, ("xrdp_orders_send_bitmap3: jpeg skipped")); - return 2; - } - LLOGLN(10, ("xrdp_orders_send_bitmap3: jpeg")); - e = width % 4; - if (e != 0) - { - e = 4 - e; - } - make_stream(xr_s); - init_stream(xr_s, 16384); - make_stream(temp_s); - init_stream(temp_s, 16384); - quality = ci->jpeg_prop[0]; - xrdp_jpeg_compress(data, width, height, xr_s, bpp, 16384, - height - 1, temp_s, e, quality); - s_mark_end(xr_s); - bufsize = (int)(xr_s->end - xr_s->data); - xrdp_orders_out_v3(self, cache_id, cache_idx, (char*)(xr_s->data), bufsize, - width + e, height, bpp,ci->v3_codec_id); - free_stream(xr_s); - free_stream(temp_s); - return 0; + + if (!xrdp_orders_send_as_jpeg(self, width, height, bpp, hints)) + { + LLOGLN(10, ("xrdp_orders_send_bitmap3: jpeg skipped")); + return 2; + } + + LLOGLN(10, ("xrdp_orders_send_bitmap3: jpeg")); + e = width % 4; + + if (e != 0) + { + e = 4 - e; + } + + make_stream(xr_s); + init_stream(xr_s, 16384); + make_stream(temp_s); + init_stream(temp_s, 16384); + quality = ci->jpeg_prop[0]; + xrdp_jpeg_compress(data, width, height, xr_s, bpp, 16384, + height - 1, temp_s, e, quality); + s_mark_end(xr_s); + bufsize = (int)(xr_s->end - xr_s->data); + xrdp_orders_out_v3(self, cache_id, cache_idx, (char *)(xr_s->data), bufsize, + width + e, height, bpp, ci->v3_codec_id); + free_stream(xr_s); + free_stream(temp_s); + return 0; #else - return 2; + return 2; #endif - } - else - { - g_writeln("xrdp_orders_send_bitmap3: todo unknown codec"); - return 1; - } - return 0; + } + else + { + g_writeln("xrdp_orders_send_bitmap3: todo unknown codec"); + return 1; + } + + return 0; } /*****************************************************************************/ /* returns error */ /* send a brush cache entry */ int APP_CC -xrdp_orders_send_brush(struct xrdp_orders* self, int width, int height, - int bpp, int type, int size, char* data, int cache_id) +xrdp_orders_send_brush(struct xrdp_orders *self, int width, int height, + int bpp, int type, int size, char *data, int cache_id) { - int order_flags = 0; - int len = 0; + int order_flags = 0; + int len = 0; - xrdp_orders_check(self, size + 12); - self->order_count++; - order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; - out_uint8(self->out_s, order_flags); - len = (size + 6) - 7; /* length after type minus 7 */ - out_uint16_le(self->out_s, len); - out_uint16_le(self->out_s, 0); /* flags */ - out_uint8(self->out_s, RDP_ORDER_BRUSHCACHE); /* type */ - out_uint8(self->out_s, cache_id); - out_uint8(self->out_s, bpp); - out_uint8(self->out_s, width); - out_uint8(self->out_s, height); - out_uint8(self->out_s, type); - out_uint8(self->out_s, size); - out_uint8a(self->out_s, data, size); - return 0; + xrdp_orders_check(self, size + 12); + self->order_count++; + order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; + out_uint8(self->out_s, order_flags); + len = (size + 6) - 7; /* length after type minus 7 */ + out_uint16_le(self->out_s, len); + out_uint16_le(self->out_s, 0); /* flags */ + out_uint8(self->out_s, RDP_ORDER_BRUSHCACHE); /* type */ + out_uint8(self->out_s, cache_id); + out_uint8(self->out_s, bpp); + out_uint8(self->out_s, width); + out_uint8(self->out_s, height); + out_uint8(self->out_s, type); + out_uint8(self->out_s, size); + out_uint8a(self->out_s, data, size); + return 0; } /*****************************************************************************/ /* returns error */ /* send an off screen bitmap entry */ int APP_CC -xrdp_orders_send_create_os_surface(struct xrdp_orders* self, int id, +xrdp_orders_send_create_os_surface(struct xrdp_orders *self, int id, int width, int height, - struct list* del_list) + struct list *del_list) { - int order_flags; - int cache_id; - int flags; - int index; - int bytes; - int num_del_list; + int order_flags; + int cache_id; + int flags; + int index; + int bytes; + int num_del_list; - bytes = 7; - num_del_list = del_list->count; - if (num_del_list > 0) - { - bytes += 2; - bytes += num_del_list * 2; - } - xrdp_orders_check(self, bytes); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 1 << 2; /* type RDP_ORDER_ALTSEC_CREATE_OFFSCR_BITMAP */ - out_uint8(self->out_s, order_flags); - cache_id = id & 0x7fff; - flags = cache_id; - if (num_del_list > 0) - { - flags |= 0x8000; - } - out_uint16_le(self->out_s, flags); - out_uint16_le(self->out_s, width); - out_uint16_le(self->out_s, height); - if (num_del_list > 0) - { - /* delete list */ - out_uint16_le(self->out_s, num_del_list); - for (index = 0; index < num_del_list; index++) + bytes = 7; + num_del_list = del_list->count; + + if (num_del_list > 0) { - cache_id = list_get_item(del_list, index) & 0x7fff; - out_uint16_le(self->out_s, cache_id); + bytes += 2; + bytes += num_del_list * 2; } - } - return 0; + + xrdp_orders_check(self, bytes); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 1 << 2; /* type RDP_ORDER_ALTSEC_CREATE_OFFSCR_BITMAP */ + out_uint8(self->out_s, order_flags); + cache_id = id & 0x7fff; + flags = cache_id; + + if (num_del_list > 0) + { + flags |= 0x8000; + } + + out_uint16_le(self->out_s, flags); + out_uint16_le(self->out_s, width); + out_uint16_le(self->out_s, height); + + if (num_del_list > 0) + { + /* delete list */ + out_uint16_le(self->out_s, num_del_list); + + for (index = 0; index < num_del_list; index++) + { + cache_id = list_get_item(del_list, index) & 0x7fff; + out_uint16_le(self->out_s, cache_id); + } + } + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_orders_send_switch_os_surface(struct xrdp_orders* self, int id) +xrdp_orders_send_switch_os_surface(struct xrdp_orders *self, int id) { - int order_flags; - int cache_id; + int order_flags; + int cache_id; - xrdp_orders_check(self, 3); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 0 << 2; /* type RDP_ORDER_ALTSEC_SWITCH_SURFACE */ - out_uint8(self->out_s, order_flags); - cache_id = id & 0xffff; - out_uint16_le(self->out_s, cache_id); - return 0; + xrdp_orders_check(self, 3); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 0 << 2; /* type RDP_ORDER_ALTSEC_SWITCH_SURFACE */ + out_uint8(self->out_s, order_flags); + cache_id = id & 0xffff; + out_uint16_le(self->out_s, cache_id); + return 0; } diff --git a/libxrdp/xrdp_orders_rail.c b/libxrdp/xrdp_orders_rail.c index 62f9b8ea..3ac0fd2a 100644 --- a/libxrdp/xrdp_orders_rail.c +++ b/libxrdp/xrdp_orders_rail.c @@ -27,26 +27,26 @@ /* RAIL */ /* returns error */ int APP_CC -xrdp_orders_send_window_delete(struct xrdp_orders* self, int window_id) +xrdp_orders_send_window_delete(struct xrdp_orders *self, int window_id) { - int order_size; - int order_flags; - int field_present_flags; + int order_size; + int order_flags; + int field_present_flags; - order_size = 11; - xrdp_orders_check(self, order_size); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ - out_uint8(self->out_s, order_flags); - /* orderSize (2 bytes) */ - out_uint16_le(self->out_s, order_size); - /* FieldsPresentFlags (4 bytes) */ - field_present_flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_STATE_DELETED; - out_uint32_le(self->out_s, field_present_flags); - /* windowId (4 bytes) */ - out_uint32_le(self->out_s, window_id); - return 0; + order_size = 11; + xrdp_orders_check(self, order_size); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ + out_uint8(self->out_s, order_flags); + /* orderSize (2 bytes) */ + out_uint16_le(self->out_s, order_size); + /* FieldsPresentFlags (4 bytes) */ + field_present_flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_STATE_DELETED; + out_uint32_le(self->out_s, field_present_flags); + /* windowId (4 bytes) */ + out_uint32_le(self->out_s, window_id); + return 0; } /*****************************************************************************/ @@ -55,69 +55,74 @@ xrdp_orders_send_window_delete(struct xrdp_orders* self, int window_id) /* flags can contain WINDOW_ORDER_STATE_NEW and/or WINDOW_ORDER_FIELD_ICON_BIG */ int APP_CC -xrdp_orders_send_window_cached_icon(struct xrdp_orders* self, +xrdp_orders_send_window_cached_icon(struct xrdp_orders *self, int window_id, int cache_entry, int cache_id, int flags) { - int order_size; - int order_flags; - int field_present_flags; + int order_size; + int order_flags; + int field_present_flags; - order_size = 14; - xrdp_orders_check(self, order_size); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ - out_uint8(self->out_s, order_flags); - /* orderSize (2 bytes) */ - out_uint16_le(self->out_s, order_size); - /* FieldsPresentFlags (4 bytes) */ - field_present_flags = flags | WINDOW_ORDER_TYPE_WINDOW | - WINDOW_ORDER_CACHED_ICON; - out_uint32_le(self->out_s, field_present_flags); - /* windowId (4 bytes) */ - out_uint32_le(self->out_s, window_id); - /* CacheEntry (2 bytes) */ - out_uint16_le(self->out_s, cache_entry); - /* CacheId (1 byte) */ - out_uint8(self->out_s, cache_id); - return 0; + order_size = 14; + xrdp_orders_check(self, order_size); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ + out_uint8(self->out_s, order_flags); + /* orderSize (2 bytes) */ + out_uint16_le(self->out_s, order_size); + /* FieldsPresentFlags (4 bytes) */ + field_present_flags = flags | WINDOW_ORDER_TYPE_WINDOW | + WINDOW_ORDER_CACHED_ICON; + out_uint32_le(self->out_s, field_present_flags); + /* windowId (4 bytes) */ + out_uint32_le(self->out_s, window_id); + /* CacheEntry (2 bytes) */ + out_uint16_le(self->out_s, cache_entry); + /* CacheId (1 byte) */ + out_uint8(self->out_s, cache_id); + return 0; } /*****************************************************************************/ /* RAIL */ /* returns error */ static int APP_CC -xrdp_orders_send_ts_icon(struct stream* s, int cache_entry, int cache_id, - struct rail_icon_info* icon_info) +xrdp_orders_send_ts_icon(struct stream *s, int cache_entry, int cache_id, + struct rail_icon_info *icon_info) { - int use_cmap; + int use_cmap; - use_cmap = 0; - if ((icon_info->bpp == 1) || (icon_info->bpp == 2) || (icon_info->bpp == 4)) - { - use_cmap = 1; - } + use_cmap = 0; - /* TS_ICON_INFO */ - out_uint16_le(s, cache_entry); - out_uint8(s, cache_id); - out_uint8(s, icon_info->bpp); - out_uint16_le(s, icon_info->width); - out_uint16_le(s, icon_info->height); - if (use_cmap) - { - out_uint16_le(s, icon_info->cmap_bytes); - } - out_uint16_le(s, icon_info->mask_bytes); - out_uint16_le(s, icon_info->data_bytes); - out_uint8p(s, icon_info->mask, icon_info->mask_bytes); - if (use_cmap) - { - out_uint8p(s, icon_info->cmap, icon_info->cmap_bytes); - } - out_uint8p(s, icon_info->data, icon_info->data_bytes); - return 0; + if ((icon_info->bpp == 1) || (icon_info->bpp == 2) || (icon_info->bpp == 4)) + { + use_cmap = 1; + } + + /* TS_ICON_INFO */ + out_uint16_le(s, cache_entry); + out_uint8(s, cache_id); + out_uint8(s, icon_info->bpp); + out_uint16_le(s, icon_info->width); + out_uint16_le(s, icon_info->height); + + if (use_cmap) + { + out_uint16_le(s, icon_info->cmap_bytes); + } + + out_uint16_le(s, icon_info->mask_bytes); + out_uint16_le(s, icon_info->data_bytes); + out_uint8p(s, icon_info->mask, icon_info->mask_bytes); + + if (use_cmap) + { + out_uint8p(s, icon_info->cmap, icon_info->cmap_bytes); + } + + out_uint8p(s, icon_info->data, icon_info->data_bytes); + return 0; } /*****************************************************************************/ @@ -126,71 +131,78 @@ xrdp_orders_send_ts_icon(struct stream* s, int cache_entry, int cache_id, /* flags can contain WINDOW_ORDER_STATE_NEW and/or WINDOW_ORDER_FIELD_ICON_BIG */ int APP_CC -xrdp_orders_send_window_icon(struct xrdp_orders* self, +xrdp_orders_send_window_icon(struct xrdp_orders *self, int window_id, int cache_entry, int cache_id, - struct rail_icon_info* icon_info, + struct rail_icon_info *icon_info, int flags) { - int order_size; - int order_flags; - int field_present_flags; - int use_cmap; + int order_size; + int order_flags; + int field_present_flags; + int use_cmap; - use_cmap = 0; - if ((icon_info->bpp == 1) || (icon_info->bpp == 2) || (icon_info->bpp == 4)) - { - use_cmap = 1; - } - order_size = 23 + icon_info->mask_bytes + icon_info->data_bytes; - if (use_cmap) - { - order_size += icon_info->cmap_bytes + 2; - } - xrdp_orders_check(self, order_size); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ - out_uint8(self->out_s, order_flags); - /* orderSize (2 bytes) */ - out_uint16_le(self->out_s, order_size); - /* FieldsPresentFlags (4 bytes) */ - field_present_flags = flags | WINDOW_ORDER_TYPE_WINDOW | - WINDOW_ORDER_ICON; - out_uint32_le(self->out_s, field_present_flags); - /* windowId (4 bytes) */ - out_uint32_le(self->out_s, window_id); + use_cmap = 0; - xrdp_orders_send_ts_icon(self->out_s, cache_entry, cache_id, icon_info); + if ((icon_info->bpp == 1) || (icon_info->bpp == 2) || (icon_info->bpp == 4)) + { + use_cmap = 1; + } - return 0; + order_size = 23 + icon_info->mask_bytes + icon_info->data_bytes; + + if (use_cmap) + { + order_size += icon_info->cmap_bytes + 2; + } + + xrdp_orders_check(self, order_size); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ + out_uint8(self->out_s, order_flags); + /* orderSize (2 bytes) */ + out_uint16_le(self->out_s, order_size); + /* FieldsPresentFlags (4 bytes) */ + field_present_flags = flags | WINDOW_ORDER_TYPE_WINDOW | + WINDOW_ORDER_ICON; + out_uint32_le(self->out_s, field_present_flags); + /* windowId (4 bytes) */ + out_uint32_le(self->out_s, window_id); + + xrdp_orders_send_ts_icon(self->out_s, cache_entry, cache_id, icon_info); + + return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_orders_send_as_unicode(struct stream* s, const char* text) +xrdp_orders_send_as_unicode(struct stream *s, const char *text) { - int str_chars; - int index; - int i32; - twchar wdst[256]; + int str_chars; + int index; + int i32; + twchar wdst[256]; - str_chars = g_mbstowcs(wdst, text, 255); - if (str_chars > 0) - { - i32 = str_chars * 2; - out_uint16_le(s, i32); - for (index = 0; index < str_chars; index++) + str_chars = g_mbstowcs(wdst, text, 255); + + if (str_chars > 0) { - i32 = wdst[index]; - out_uint16_le(s, i32); + i32 = str_chars * 2; + out_uint16_le(s, i32); + + for (index = 0; index < str_chars; index++) + { + i32 = wdst[index]; + out_uint16_le(s, i32); + } } - } - else - { - out_uint16_le(s, 0); - } - return 0; + else + { + out_uint16_le(s, 0); + } + + return 0; } /*****************************************************************************/ @@ -198,247 +210,276 @@ xrdp_orders_send_as_unicode(struct stream* s, const char* text) /* returns error */ /* flags can contain WINDOW_ORDER_STATE_NEW */ int APP_CC -xrdp_orders_send_window_new_update(struct xrdp_orders* self, int window_id, - struct rail_window_state_order* window_state, +xrdp_orders_send_window_new_update(struct xrdp_orders *self, int window_id, + struct rail_window_state_order *window_state, int flags) { - int order_size; - int order_flags; - int field_present_flags; - int num_chars; - int index; + int order_size; + int order_flags; + int field_present_flags; + int num_chars; + int index; - order_size = 11; - field_present_flags = flags | WINDOW_ORDER_TYPE_WINDOW; - if (field_present_flags & WINDOW_ORDER_FIELD_OWNER) - { - /* ownerWindowId (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_STYLE) - { - /* style (4 bytes) */ - order_size += 4; - /* extendedStyle (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_SHOW) - { - /* showState (1 byte) */ - order_size += 1; - } - if (field_present_flags & WINDOW_ORDER_FIELD_TITLE) - { - /* titleInfo */ - num_chars = g_mbstowcs(0, window_state->title_info, 0); - order_size += 2 * num_chars + 2; - } - if (field_present_flags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) - { - /* clientOffsetX (4 bytes) */ - order_size += 4; - /* clientOffsetY (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) - { - /* clientAreaWidth (4 bytes) */ - order_size += 4; - /* clientAreaHeight (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_RP_CONTENT) - { - /* RPContent (1 byte) */ - order_size += 1; - } - if (field_present_flags & WINDOW_ORDER_FIELD_ROOT_PARENT) - { - /* rootParentHandle (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_WND_OFFSET) - { - /* windowOffsetX (4 bytes) */ - order_size += 4; - /* windowOffsetY (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) - { - /* windowClientDeltaX (4 bytes) */ - order_size += 4; - /* windowClientDeltaY (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_WND_SIZE) - { - /* windowWidth (4 bytes) */ - order_size += 4; - /* windowHeight (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_WND_RECTS) - { - /* numWindowRects (2 bytes) */ - order_size += 2; - order_size += 8 * window_state->num_window_rects; - } - if (field_present_flags & WINDOW_ORDER_FIELD_VIS_OFFSET) - { - /* visibleOffsetX (4 bytes) */ - order_size += 4; - /* visibleOffsetY (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_VISIBILITY) - { - /* numVisibilityRects (2 bytes) */ - order_size += 2; - order_size += 8 * window_state->num_visibility_rects; - } + order_size = 11; + field_present_flags = flags | WINDOW_ORDER_TYPE_WINDOW; - xrdp_orders_check(self, order_size); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ - out_uint8(self->out_s, order_flags); - /* orderSize (2 bytes) */ - out_uint16_le(self->out_s, order_size); - /* FieldsPresentFlags (4 bytes) */ - out_uint32_le(self->out_s, field_present_flags); - /* windowId (4 bytes) */ - out_uint32_le(self->out_s, window_id); - - if (field_present_flags & WINDOW_ORDER_FIELD_OWNER) - { - /* ownerWindowId (4 bytes) */ - out_uint32_le(self->out_s, window_state->owner_window_id); - } - if (field_present_flags & WINDOW_ORDER_FIELD_STYLE) - { - /* style (4 bytes) */ - out_uint32_le(self->out_s, window_state->style); - /* extendedStyle (4 bytes) */ - out_uint32_le(self->out_s, window_state->extended_style); - } - if (field_present_flags & WINDOW_ORDER_FIELD_SHOW) - { - /* showState (1 byte) */ - out_uint8(self->out_s, window_state->show_state); - } - if (field_present_flags & WINDOW_ORDER_FIELD_TITLE) - { - /* titleInfo */ - xrdp_orders_send_as_unicode(self->out_s, window_state->title_info); - } - if (field_present_flags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) - { - /* clientOffsetX (4 bytes) */ - out_uint32_le(self->out_s, window_state->client_offset_x); - /* clientOffsetY (4 bytes) */ - out_uint32_le(self->out_s, window_state->client_offset_y); - } - if (field_present_flags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) - { - /* clientAreaWidth (4 bytes) */ - out_uint32_le(self->out_s, window_state->client_area_width); - /* clientAreaHeight (4 bytes) */ - out_uint32_le(self->out_s, window_state->client_area_height); - } - if (field_present_flags & WINDOW_ORDER_FIELD_RP_CONTENT) - { - /* RPContent (1 byte) */ - out_uint8(self->out_s, window_state->rp_content); - } - if (field_present_flags & WINDOW_ORDER_FIELD_ROOT_PARENT) - { - /* rootParentHandle (4 bytes) */ - out_uint32_le(self->out_s, window_state->root_parent_handle); - } - if (field_present_flags & WINDOW_ORDER_FIELD_WND_OFFSET) - { - /* windowOffsetX (4 bytes) */ - out_uint32_le(self->out_s, window_state->window_offset_x); - /* windowOffsetY (4 bytes) */ - out_uint32_le(self->out_s, window_state->window_offset_y); - } - if (field_present_flags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) - { - /* windowClientDeltaX (4 bytes) */ - out_uint32_le(self->out_s, window_state->window_client_delta_x); - /* windowClientDeltaY (4 bytes) */ - out_uint32_le(self->out_s, window_state->window_client_delta_y); - } - if (field_present_flags & WINDOW_ORDER_FIELD_WND_SIZE) - { - /* windowWidth (4 bytes) */ - out_uint32_le(self->out_s, window_state->window_width); - /* windowHeight (4 bytes) */ - out_uint32_le(self->out_s, window_state->window_height); - } - if (field_present_flags & WINDOW_ORDER_FIELD_WND_RECTS) - { - /* numWindowRects (2 bytes) */ - out_uint16_le(self->out_s, window_state->num_window_rects); - for (index = 0; index < window_state->num_window_rects; index++) + if (field_present_flags & WINDOW_ORDER_FIELD_OWNER) { - out_uint16_le(self->out_s, window_state->window_rects[index].left); - out_uint16_le(self->out_s, window_state->window_rects[index].top); - out_uint16_le(self->out_s, window_state->window_rects[index].right); - out_uint16_le(self->out_s, window_state->window_rects[index].bottom); + /* ownerWindowId (4 bytes) */ + order_size += 4; } - } - if (field_present_flags & WINDOW_ORDER_FIELD_VIS_OFFSET) - { - /* visibleOffsetX (4 bytes) */ - out_uint32_le(self->out_s, window_state->visible_offset_x); - /* visibleOffsetY (4 bytes) */ - out_uint32_le(self->out_s, window_state->visible_offset_y); - } - if (field_present_flags & WINDOW_ORDER_FIELD_VISIBILITY) - { - /* numVisibilityRects (2 bytes) */ - out_uint16_le(self->out_s, window_state->num_visibility_rects); - for (index = 0; index < window_state->num_visibility_rects; index++) - { - out_uint16_le(self->out_s, window_state->visibility_rects[index].left); - out_uint16_le(self->out_s, window_state->visibility_rects[index].top); - out_uint16_le(self->out_s, window_state->visibility_rects[index].right); - out_uint16_le(self->out_s, window_state->visibility_rects[index].bottom); - } - } - return 0; + if (field_present_flags & WINDOW_ORDER_FIELD_STYLE) + { + /* style (4 bytes) */ + order_size += 4; + /* extendedStyle (4 bytes) */ + order_size += 4; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_SHOW) + { + /* showState (1 byte) */ + order_size += 1; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_TITLE) + { + /* titleInfo */ + num_chars = g_mbstowcs(0, window_state->title_info, 0); + order_size += 2 * num_chars + 2; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) + { + /* clientOffsetX (4 bytes) */ + order_size += 4; + /* clientOffsetY (4 bytes) */ + order_size += 4; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) + { + /* clientAreaWidth (4 bytes) */ + order_size += 4; + /* clientAreaHeight (4 bytes) */ + order_size += 4; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_RP_CONTENT) + { + /* RPContent (1 byte) */ + order_size += 1; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_ROOT_PARENT) + { + /* rootParentHandle (4 bytes) */ + order_size += 4; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_WND_OFFSET) + { + /* windowOffsetX (4 bytes) */ + order_size += 4; + /* windowOffsetY (4 bytes) */ + order_size += 4; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) + { + /* windowClientDeltaX (4 bytes) */ + order_size += 4; + /* windowClientDeltaY (4 bytes) */ + order_size += 4; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_WND_SIZE) + { + /* windowWidth (4 bytes) */ + order_size += 4; + /* windowHeight (4 bytes) */ + order_size += 4; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_WND_RECTS) + { + /* numWindowRects (2 bytes) */ + order_size += 2; + order_size += 8 * window_state->num_window_rects; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_VIS_OFFSET) + { + /* visibleOffsetX (4 bytes) */ + order_size += 4; + /* visibleOffsetY (4 bytes) */ + order_size += 4; + } + + if (field_present_flags & WINDOW_ORDER_FIELD_VISIBILITY) + { + /* numVisibilityRects (2 bytes) */ + order_size += 2; + order_size += 8 * window_state->num_visibility_rects; + } + + xrdp_orders_check(self, order_size); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ + out_uint8(self->out_s, order_flags); + /* orderSize (2 bytes) */ + out_uint16_le(self->out_s, order_size); + /* FieldsPresentFlags (4 bytes) */ + out_uint32_le(self->out_s, field_present_flags); + /* windowId (4 bytes) */ + out_uint32_le(self->out_s, window_id); + + if (field_present_flags & WINDOW_ORDER_FIELD_OWNER) + { + /* ownerWindowId (4 bytes) */ + out_uint32_le(self->out_s, window_state->owner_window_id); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_STYLE) + { + /* style (4 bytes) */ + out_uint32_le(self->out_s, window_state->style); + /* extendedStyle (4 bytes) */ + out_uint32_le(self->out_s, window_state->extended_style); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_SHOW) + { + /* showState (1 byte) */ + out_uint8(self->out_s, window_state->show_state); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_TITLE) + { + /* titleInfo */ + xrdp_orders_send_as_unicode(self->out_s, window_state->title_info); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) + { + /* clientOffsetX (4 bytes) */ + out_uint32_le(self->out_s, window_state->client_offset_x); + /* clientOffsetY (4 bytes) */ + out_uint32_le(self->out_s, window_state->client_offset_y); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) + { + /* clientAreaWidth (4 bytes) */ + out_uint32_le(self->out_s, window_state->client_area_width); + /* clientAreaHeight (4 bytes) */ + out_uint32_le(self->out_s, window_state->client_area_height); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_RP_CONTENT) + { + /* RPContent (1 byte) */ + out_uint8(self->out_s, window_state->rp_content); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_ROOT_PARENT) + { + /* rootParentHandle (4 bytes) */ + out_uint32_le(self->out_s, window_state->root_parent_handle); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_WND_OFFSET) + { + /* windowOffsetX (4 bytes) */ + out_uint32_le(self->out_s, window_state->window_offset_x); + /* windowOffsetY (4 bytes) */ + out_uint32_le(self->out_s, window_state->window_offset_y); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) + { + /* windowClientDeltaX (4 bytes) */ + out_uint32_le(self->out_s, window_state->window_client_delta_x); + /* windowClientDeltaY (4 bytes) */ + out_uint32_le(self->out_s, window_state->window_client_delta_y); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_WND_SIZE) + { + /* windowWidth (4 bytes) */ + out_uint32_le(self->out_s, window_state->window_width); + /* windowHeight (4 bytes) */ + out_uint32_le(self->out_s, window_state->window_height); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_WND_RECTS) + { + /* numWindowRects (2 bytes) */ + out_uint16_le(self->out_s, window_state->num_window_rects); + + for (index = 0; index < window_state->num_window_rects; index++) + { + out_uint16_le(self->out_s, window_state->window_rects[index].left); + out_uint16_le(self->out_s, window_state->window_rects[index].top); + out_uint16_le(self->out_s, window_state->window_rects[index].right); + out_uint16_le(self->out_s, window_state->window_rects[index].bottom); + } + } + + if (field_present_flags & WINDOW_ORDER_FIELD_VIS_OFFSET) + { + /* visibleOffsetX (4 bytes) */ + out_uint32_le(self->out_s, window_state->visible_offset_x); + /* visibleOffsetY (4 bytes) */ + out_uint32_le(self->out_s, window_state->visible_offset_y); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_VISIBILITY) + { + /* numVisibilityRects (2 bytes) */ + out_uint16_le(self->out_s, window_state->num_visibility_rects); + + for (index = 0; index < window_state->num_visibility_rects; index++) + { + out_uint16_le(self->out_s, window_state->visibility_rects[index].left); + out_uint16_le(self->out_s, window_state->visibility_rects[index].top); + out_uint16_le(self->out_s, window_state->visibility_rects[index].right); + out_uint16_le(self->out_s, window_state->visibility_rects[index].bottom); + } + } + + return 0; } /*****************************************************************************/ /* RAIL */ /* returns error */ int APP_CC -xrdp_orders_send_notify_delete(struct xrdp_orders* self, int window_id, +xrdp_orders_send_notify_delete(struct xrdp_orders *self, int window_id, int notify_id) { - int order_size; - int order_flags; - int field_present_flags; + int order_size; + int order_flags; + int field_present_flags; - order_size = 15; - xrdp_orders_check(self, order_size); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ - out_uint8(self->out_s, order_flags); - /* orderSize (2 bytes) */ - out_uint16_le(self->out_s, order_size); - /* FieldsPresentFlags (4 bytes) */ - field_present_flags = WINDOW_ORDER_TYPE_NOTIFY | WINDOW_ORDER_STATE_DELETED; - out_uint32_le(self->out_s, field_present_flags); - /* windowId (4 bytes) */ - out_uint32_le(self->out_s, window_id); - /* notifyIconId (4 bytes) */ - out_uint32_le(self->out_s, notify_id); - return 0; + order_size = 15; + xrdp_orders_check(self, order_size); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ + out_uint8(self->out_s, order_flags); + /* orderSize (2 bytes) */ + out_uint16_le(self->out_s, order_size); + /* FieldsPresentFlags (4 bytes) */ + field_present_flags = WINDOW_ORDER_TYPE_NOTIFY | WINDOW_ORDER_STATE_DELETED; + out_uint32_le(self->out_s, field_present_flags); + /* windowId (4 bytes) */ + out_uint32_le(self->out_s, window_id); + /* notifyIconId (4 bytes) */ + out_uint32_le(self->out_s, notify_id); + return 0; } /*****************************************************************************/ @@ -446,123 +487,137 @@ xrdp_orders_send_notify_delete(struct xrdp_orders* self, int window_id, /* returns error */ /* flags can contain WINDOW_ORDER_STATE_NEW */ int APP_CC -xrdp_orders_send_notify_new_update(struct xrdp_orders* self, +xrdp_orders_send_notify_new_update(struct xrdp_orders *self, int window_id, int notify_id, - struct rail_notify_state_order* notify_state, + struct rail_notify_state_order *notify_state, int flags) { - int order_size; - int order_flags; - int field_present_flags; - int num_chars; - int use_cmap; + int order_size; + int order_flags; + int field_present_flags; + int num_chars; + int use_cmap; - order_size = 15; - field_present_flags = flags | WINDOW_ORDER_TYPE_NOTIFY; - if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) - { - /* Version (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_TIP) - { - /* ToolTip (variable) UNICODE_STRING */ - num_chars = g_mbstowcs(0, notify_state->tool_tip, 0); - order_size += 2 * num_chars + 2; - } - if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) - { - /* InfoTip (variable) TS_NOTIFY_ICON_INFOTIP */ - /* UNICODE_STRING */ - num_chars = g_mbstowcs(0, notify_state->infotip.title, 0); - order_size += 2 * num_chars + 2; - /* UNICODE_STRING */ - num_chars = g_mbstowcs(0, notify_state->infotip.text, 0); - order_size += 2 * num_chars + 2; - /* Timeout (4 bytes) */ - /* InfoFlags (4 bytes) */ - order_size += 8; - } - if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_STATE) - { - /* State (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_ICON) - { - /* Icon (variable) */ - use_cmap = 0; - if ((notify_state->icon_info.bpp == 1) || (notify_state->icon_info.bpp == 2) || - (notify_state->icon_info.bpp == 4)) + order_size = 15; + field_present_flags = flags | WINDOW_ORDER_TYPE_NOTIFY; + + if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) { - use_cmap = 1; + /* Version (4 bytes) */ + order_size += 4; } - order_size += 12 + notify_state->icon_info.mask_bytes + - notify_state->icon_info.data_bytes; - if (use_cmap) + + if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_TIP) { - order_size += notify_state->icon_info.cmap_bytes + 2; + /* ToolTip (variable) UNICODE_STRING */ + num_chars = g_mbstowcs(0, notify_state->tool_tip, 0); + order_size += 2 * num_chars + 2; } - } - if (field_present_flags & WINDOW_ORDER_CACHED_ICON) - { - /* CachedIcon (3 bytes) */ - order_size += 3; - } - xrdp_orders_check(self, order_size); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ - out_uint8(self->out_s, order_flags); - /* orderSize (2 bytes) */ - out_uint16_le(self->out_s, order_size); - /* FieldsPresentFlags (4 bytes) */ - out_uint32_le(self->out_s, field_present_flags); - /* windowId (4 bytes) */ - out_uint32_le(self->out_s, window_id); - /* notifyIconId (4 bytes) */ - out_uint32_le(self->out_s, notify_id); + if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) + { + /* InfoTip (variable) TS_NOTIFY_ICON_INFOTIP */ + /* UNICODE_STRING */ + num_chars = g_mbstowcs(0, notify_state->infotip.title, 0); + order_size += 2 * num_chars + 2; + /* UNICODE_STRING */ + num_chars = g_mbstowcs(0, notify_state->infotip.text, 0); + order_size += 2 * num_chars + 2; + /* Timeout (4 bytes) */ + /* InfoFlags (4 bytes) */ + order_size += 8; + } - if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) - { - /* Version (4 bytes) */ - out_uint32_le(self->out_s, notify_state->version); - } - if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_TIP) - { - /* ToolTip (variable) UNICODE_STRING */ - xrdp_orders_send_as_unicode(self->out_s, notify_state->tool_tip); - } - if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) - { - /* InfoTip (variable) TS_NOTIFY_ICON_INFOTIP */ - out_uint32_le(self->out_s, notify_state->infotip.timeout); - out_uint32_le(self->out_s, notify_state->infotip.flags); - xrdp_orders_send_as_unicode(self->out_s, notify_state->infotip.text); - xrdp_orders_send_as_unicode(self->out_s, notify_state->infotip.title); - } - if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_STATE) - { - /* State (4 bytes) */ - out_uint32_le(self->out_s, notify_state->state); - } - if (field_present_flags & WINDOW_ORDER_ICON) - { - /* Icon (variable) */ - xrdp_orders_send_ts_icon(self->out_s, notify_state->icon_cache_entry, - notify_state->icon_cache_id, - ¬ify_state->icon_info); - } - if (field_present_flags & WINDOW_ORDER_CACHED_ICON) - { - /* CacheEntry (2 bytes) */ - out_uint16_le(self->out_s, notify_state->icon_cache_entry); - /* CacheId (1 byte) */ - out_uint8(self->out_s, notify_state->icon_cache_id); - } + if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_STATE) + { + /* State (4 bytes) */ + order_size += 4; + } - return 0; + if (field_present_flags & WINDOW_ORDER_ICON) + { + /* Icon (variable) */ + use_cmap = 0; + + if ((notify_state->icon_info.bpp == 1) || (notify_state->icon_info.bpp == 2) || + (notify_state->icon_info.bpp == 4)) + { + use_cmap = 1; + } + + order_size += 12 + notify_state->icon_info.mask_bytes + + notify_state->icon_info.data_bytes; + + if (use_cmap) + { + order_size += notify_state->icon_info.cmap_bytes + 2; + } + } + + if (field_present_flags & WINDOW_ORDER_CACHED_ICON) + { + /* CachedIcon (3 bytes) */ + order_size += 3; + } + + xrdp_orders_check(self, order_size); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ + out_uint8(self->out_s, order_flags); + /* orderSize (2 bytes) */ + out_uint16_le(self->out_s, order_size); + /* FieldsPresentFlags (4 bytes) */ + out_uint32_le(self->out_s, field_present_flags); + /* windowId (4 bytes) */ + out_uint32_le(self->out_s, window_id); + /* notifyIconId (4 bytes) */ + out_uint32_le(self->out_s, notify_id); + + if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) + { + /* Version (4 bytes) */ + out_uint32_le(self->out_s, notify_state->version); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_TIP) + { + /* ToolTip (variable) UNICODE_STRING */ + xrdp_orders_send_as_unicode(self->out_s, notify_state->tool_tip); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) + { + /* InfoTip (variable) TS_NOTIFY_ICON_INFOTIP */ + out_uint32_le(self->out_s, notify_state->infotip.timeout); + out_uint32_le(self->out_s, notify_state->infotip.flags); + xrdp_orders_send_as_unicode(self->out_s, notify_state->infotip.text); + xrdp_orders_send_as_unicode(self->out_s, notify_state->infotip.title); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_NOTIFY_STATE) + { + /* State (4 bytes) */ + out_uint32_le(self->out_s, notify_state->state); + } + + if (field_present_flags & WINDOW_ORDER_ICON) + { + /* Icon (variable) */ + xrdp_orders_send_ts_icon(self->out_s, notify_state->icon_cache_entry, + notify_state->icon_cache_id, + ¬ify_state->icon_info); + } + + if (field_present_flags & WINDOW_ORDER_CACHED_ICON) + { + /* CacheEntry (2 bytes) */ + out_uint16_le(self->out_s, notify_state->icon_cache_entry); + /* CacheId (1 byte) */ + out_uint8(self->out_s, notify_state->icon_cache_id); + } + + return 0; } /*****************************************************************************/ @@ -570,56 +625,59 @@ xrdp_orders_send_notify_new_update(struct xrdp_orders* self, /* returns error */ /* used for both Non-Monitored Desktop and Actively Monitored Desktop */ int APP_CC -xrdp_orders_send_monitored_desktop(struct xrdp_orders* self, - struct rail_monitored_desktop_order* mdo, +xrdp_orders_send_monitored_desktop(struct xrdp_orders *self, + struct rail_monitored_desktop_order *mdo, int flags) { - int order_size; - int order_flags; - int field_present_flags; - int index; + int order_size; + int order_flags; + int field_present_flags; + int index; - order_size = 7; - field_present_flags = flags | WINDOW_ORDER_TYPE_DESKTOP; + order_size = 7; + field_present_flags = flags | WINDOW_ORDER_TYPE_DESKTOP; - if (field_present_flags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND) - { - /* ActiveWindowId (4 bytes) */ - order_size += 4; - } - if (field_present_flags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER) - { - /* NumWindowIds (1 byte) */ - order_size += 1; - /* WindowIds (variable) */ - order_size += mdo->num_window_ids * 4; - } - - xrdp_orders_check(self, order_size); - self->order_count++; - order_flags = RDP_ORDER_SECONDARY; - order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ - out_uint8(self->out_s, order_flags); - /* orderSize (2 bytes) */ - out_uint16_le(self->out_s, order_size); - /* FieldsPresentFlags (4 bytes) */ - out_uint32_le(self->out_s, field_present_flags); - - if (field_present_flags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND) - { - /* ActiveWindowId (4 bytes) */ - out_uint32_le(self->out_s, mdo->active_window_id); - } - if (field_present_flags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER) - { - /* NumWindowIds (1 byte) */ - out_uint8(self->out_s, mdo->num_window_ids); - /* WindowIds (variable) */ - for (index = 0; index < mdo->num_window_ids; index++) + if (field_present_flags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND) { - out_uint32_le(self->out_s, mdo->window_ids[index]); + /* ActiveWindowId (4 bytes) */ + order_size += 4; } - } - return 0; + if (field_present_flags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER) + { + /* NumWindowIds (1 byte) */ + order_size += 1; + /* WindowIds (variable) */ + order_size += mdo->num_window_ids * 4; + } + + xrdp_orders_check(self, order_size); + self->order_count++; + order_flags = RDP_ORDER_SECONDARY; + order_flags |= 0xb << 2; /* type TS_ALTSEC_WINDOW */ + out_uint8(self->out_s, order_flags); + /* orderSize (2 bytes) */ + out_uint16_le(self->out_s, order_size); + /* FieldsPresentFlags (4 bytes) */ + out_uint32_le(self->out_s, field_present_flags); + + if (field_present_flags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND) + { + /* ActiveWindowId (4 bytes) */ + out_uint32_le(self->out_s, mdo->active_window_id); + } + + if (field_present_flags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER) + { + /* NumWindowIds (1 byte) */ + out_uint8(self->out_s, mdo->num_window_ids); + + /* WindowIds (variable) */ + for (index = 0; index < mdo->num_window_ids; index++) + { + out_uint32_le(self->out_s, mdo->window_ids[index]); + } + } + + return 0; } diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index 53e3ddc2..bf0f8f4e 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - rdp layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * rdp layer + */ #include "libxrdp.h" @@ -29,28 +27,30 @@ /* some compilers need unsigned char to avoid warnings */ static tui8 g_unknown1[172] = -{ 0xff, 0x02, 0xb6, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x27, 0x00, 0x03, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x26, 0x00, 0x01, 0x00, 0x1e, 0x00, - 0x02, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x1d, 0x00, - 0x04, 0x00, 0x27, 0x00, 0x05, 0x00, 0x0b, 0x00, - 0x06, 0x00, 0x28, 0x00, 0x08, 0x00, 0x21, 0x00, - 0x09, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x22, 0x00, - 0x0b, 0x00, 0x25, 0x00, 0x0c, 0x00, 0x24, 0x00, - 0x0d, 0x00, 0x23, 0x00, 0x0e, 0x00, 0x19, 0x00, - 0x0f, 0x00, 0x16, 0x00, 0x10, 0x00, 0x15, 0x00, - 0x11, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x1b, 0x00, - 0x13, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x17, 0x00, - 0x15, 0x00, 0x18, 0x00, 0x16, 0x00, 0x0e, 0x00, - 0x18, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, - 0x1a, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x14, 0x00, - 0x1f, 0x00, 0x13, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x0a, 0x00, 0x22, 0x00, 0x06, 0x00, - 0x23, 0x00, 0x07, 0x00, 0x24, 0x00, 0x08, 0x00, - 0x25, 0x00, 0x09, 0x00, 0x26, 0x00, 0x04, 0x00, - 0x27, 0x00, 0x03, 0x00, 0x28, 0x00, 0x02, 0x00, - 0x29, 0x00, 0x01, 0x00, 0x2a, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x2a, 0x00 }; +{ + 0xff, 0x02, 0xb6, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x27, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x26, 0x00, 0x01, 0x00, 0x1e, 0x00, + 0x02, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x1d, 0x00, + 0x04, 0x00, 0x27, 0x00, 0x05, 0x00, 0x0b, 0x00, + 0x06, 0x00, 0x28, 0x00, 0x08, 0x00, 0x21, 0x00, + 0x09, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x22, 0x00, + 0x0b, 0x00, 0x25, 0x00, 0x0c, 0x00, 0x24, 0x00, + 0x0d, 0x00, 0x23, 0x00, 0x0e, 0x00, 0x19, 0x00, + 0x0f, 0x00, 0x16, 0x00, 0x10, 0x00, 0x15, 0x00, + 0x11, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x1b, 0x00, + 0x13, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x17, 0x00, + 0x15, 0x00, 0x18, 0x00, 0x16, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, + 0x1a, 0x00, 0x12, 0x00, 0x1b, 0x00, 0x14, 0x00, + 0x1f, 0x00, 0x13, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x0a, 0x00, 0x22, 0x00, 0x06, 0x00, + 0x23, 0x00, 0x07, 0x00, 0x24, 0x00, 0x08, 0x00, + 0x25, 0x00, 0x09, 0x00, 0x26, 0x00, 0x04, 0x00, + 0x27, 0x00, 0x03, 0x00, 0x28, 0x00, 0x02, 0x00, + 0x29, 0x00, 0x01, 0x00, 0x2a, 0x00, 0x05, 0x00, + 0x2b, 0x00, 0x2a, 0x00 +}; /* some compilers need unsigned char to avoid warnings */ /* @@ -60,113 +60,116 @@ static tui8 g_unknown2[8] = /*****************************************************************************/ static int APP_CC -xrdp_rdp_read_config(struct xrdp_client_info* client_info) +xrdp_rdp_read_config(struct xrdp_client_info *client_info) { - int index = 0; - struct list* items = (struct list *)NULL; - struct list* values = (struct list *)NULL; - char* item = (char *)NULL; - char* value = (char *)NULL; - char cfg_file[256]; + int index = 0; + struct list *items = (struct list *)NULL; + struct list *values = (struct list *)NULL; + char *item = (char *)NULL; + char *value = (char *)NULL; + char cfg_file[256]; - /* initialize (zero out) local variables: */ - g_memset(cfg_file,0,sizeof(char) * 256); + /* initialize (zero out) local variables: */ + g_memset(cfg_file, 0, sizeof(char) * 256); - items = list_create(); - items->auto_free = 1; - values = list_create(); - values->auto_free = 1; - g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); - file_by_name_read_section(cfg_file, "globals", items, values); - for (index = 0; index < items->count; index++) - { - item = (char*)list_get_item(items, index); - value = (char*)list_get_item(values, index); - if (g_strcasecmp(item, "bitmap_cache") == 0) + items = list_create(); + items->auto_free = 1; + values = list_create(); + values->auto_free = 1; + g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + file_by_name_read_section(cfg_file, "globals", items, values); + + for (index = 0; index < items->count; index++) { - if ((g_strcasecmp(value, "yes") == 0) || - (g_strcasecmp(value, "true") == 0) || - (g_strcasecmp(value, "1") == 0)) - { - client_info->use_bitmap_cache = 1; - } + item = (char *)list_get_item(items, index); + value = (char *)list_get_item(values, index); + + if (g_strcasecmp(item, "bitmap_cache") == 0) + { + if ((g_strcasecmp(value, "yes") == 0) || + (g_strcasecmp(value, "true") == 0) || + (g_strcasecmp(value, "1") == 0)) + { + client_info->use_bitmap_cache = 1; + } + } + else if (g_strcasecmp(item, "bitmap_compression") == 0) + { + if (g_strcasecmp(value, "yes") == 0 || + g_strcasecmp(value, "true") == 0 || + g_strcasecmp(value, "1") == 0) + { + client_info->use_bitmap_comp = 1; + } + } + else if (g_strcasecmp(item, "crypt_level") == 0) + { + if (g_strcasecmp(value, "low") == 0) + { + client_info->crypt_level = 1; + } + else if (g_strcasecmp(value, "medium") == 0) + { + client_info->crypt_level = 2; + } + else if (g_strcasecmp(value, "high") == 0) + { + client_info->crypt_level = 3; + } + else + { + g_writeln("Warning: Your configured crypt level is" + "undefined 'high' will be used"); + client_info->crypt_level = 3; + } + } + else if (g_strcasecmp(item, "channel_code") == 0) + { + if ((g_strcasecmp(value, "yes") == 0) || + (g_strcasecmp(value, "1") == 0) || + (g_strcasecmp(value, "true") == 0)) + { + client_info->channel_code = 1; + } + else + { + g_writeln("Info: All channels are disabled"); + } + } + else if (g_strcasecmp(item, "max_bpp") == 0) + { + client_info->max_bpp = g_atoi(value); + } } - else if (g_strcasecmp(item, "bitmap_compression") == 0) - { - if (g_strcasecmp(value, "yes") == 0 || - g_strcasecmp(value, "true") == 0 || - g_strcasecmp(value, "1") == 0) - { - client_info->use_bitmap_comp = 1; - } - } - else if (g_strcasecmp(item, "crypt_level") == 0) - { - if (g_strcasecmp(value, "low") == 0) - { - client_info->crypt_level = 1; - } - else if (g_strcasecmp(value, "medium") == 0) - { - client_info->crypt_level = 2; - } - else if (g_strcasecmp(value, "high") == 0) - { - client_info->crypt_level = 3; - } - else - { - g_writeln("Warning: Your configured crypt level is" - "undefined 'high' will be used"); - client_info->crypt_level = 3; - } - } - else if (g_strcasecmp(item, "channel_code") == 0) - { - if ((g_strcasecmp(value, "yes") == 0) || - (g_strcasecmp(value, "1") == 0) || - (g_strcasecmp(value, "true") == 0)) - { - client_info->channel_code = 1; - } - else - { - g_writeln("Info: All channels are disabled"); - } - } - else if (g_strcasecmp(item, "max_bpp") == 0) - { - client_info->max_bpp = g_atoi(value); - } - } - list_delete(items); - list_delete(values); - return 0; + + list_delete(items); + list_delete(values); + return 0; } #if defined(XRDP_FREERDP1) /*****************************************************************************/ static void -cpuid(tui32 info, tui32* eax, tui32* ebx, tui32* ecx, tui32* edx) +cpuid(tui32 info, tui32 *eax, tui32 *ebx, tui32 *ecx, tui32 *edx) { #ifdef __GNUC__ #if defined(__i386__) || defined(__x86_64__) - __asm volatile - ( - /* The EBX (or RBX register on x86_64) is used for the PIC base address - and must not be corrupted by our inline assembly. */ + __asm volatile + ( + /* The EBX (or RBX register on x86_64) is used for the PIC base address + and must not be corrupted by our inline assembly. */ #if defined(__i386__) - "mov %%ebx, %%esi;" - "cpuid;" - "xchg %%ebx, %%esi;" + "mov %%ebx, %%esi;" + "cpuid;" + "xchg %%ebx, %%esi;" #else - "mov %%rbx, %%rsi;" - "cpuid;" - "xchg %%rbx, %%rsi;" + "mov %%rbx, %%rsi;" + "cpuid;" + "xchg %%rbx, %%rsi;" #endif - : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) - : "0" (info) - ); + : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (info) + ); #endif #endif } @@ -175,1379 +178,1457 @@ cpuid(tui32 info, tui32* eax, tui32* ebx, tui32* ecx, tui32* edx) static tui32 xrdp_rdp_detect_cpu(void) { - tui32 eax; - tui32 ebx; - tui32 ecx; - tui32 edx; - tui32 cpu_opt; + tui32 eax; + tui32 ebx; + tui32 ecx; + tui32 edx; + tui32 cpu_opt; - eax = 0; - ebx = 0; - ecx = 0; - edx = 0; - cpu_opt = 0; - cpuid(1, &eax, &ebx, &ecx, &edx); + eax = 0; + ebx = 0; + ecx = 0; + edx = 0; + cpu_opt = 0; + cpuid(1, &eax, &ebx, &ecx, &edx); - if (edx & (1 << 26)) - { - DEBUG("SSE2 detected"); - cpu_opt |= CPU_SSE2; - } + if (edx & (1 << 26)) + { + DEBUG("SSE2 detected"); + cpu_opt |= CPU_SSE2; + } - return cpu_opt; + return cpu_opt; } #endif /*****************************************************************************/ -struct xrdp_rdp* APP_CC -xrdp_rdp_create(struct xrdp_session* session, struct trans* trans) +struct xrdp_rdp *APP_CC +xrdp_rdp_create(struct xrdp_session *session, struct trans *trans) { - struct xrdp_rdp* self = (struct xrdp_rdp *)NULL; - int bytes; + struct xrdp_rdp *self = (struct xrdp_rdp *)NULL; + int bytes; - DEBUG(("in xrdp_rdp_create")); - self = (struct xrdp_rdp*)g_malloc(sizeof(struct xrdp_rdp), 1); - self->session = session; - self->share_id = 66538; - /* read ini settings */ - xrdp_rdp_read_config(&self->client_info); - /* create sec layer */ - self->sec_layer = xrdp_sec_create(self, trans, self->client_info.crypt_level, - self->client_info.channel_code); - /* default 8 bit v1 color bitmap cache entries and size */ - self->client_info.cache1_entries = 600; - self->client_info.cache1_size = 256; - self->client_info.cache2_entries = 300; - self->client_info.cache2_size = 1024; - self->client_info.cache3_entries = 262; - self->client_info.cache3_size = 4096; - /* load client ip info */ - bytes = sizeof(self->client_info.client_ip) - 1; - g_write_ip_address(trans->sck, self->client_info.client_ip, bytes); + DEBUG(("in xrdp_rdp_create")); + self = (struct xrdp_rdp *)g_malloc(sizeof(struct xrdp_rdp), 1); + self->session = session; + self->share_id = 66538; + /* read ini settings */ + xrdp_rdp_read_config(&self->client_info); + /* create sec layer */ + self->sec_layer = xrdp_sec_create(self, trans, self->client_info.crypt_level, + self->client_info.channel_code); + /* default 8 bit v1 color bitmap cache entries and size */ + self->client_info.cache1_entries = 600; + self->client_info.cache1_size = 256; + self->client_info.cache2_entries = 300; + self->client_info.cache2_size = 1024; + self->client_info.cache3_entries = 262; + self->client_info.cache3_size = 4096; + /* load client ip info */ + bytes = sizeof(self->client_info.client_ip) - 1; + g_write_ip_address(trans->sck, self->client_info.client_ip, bytes); #if defined(XRDP_FREERDP1) - self->mppc_enc = mppc_enc_new(PROTO_RDP_50); - self->rfx_enc = rfx_context_new(); - rfx_context_set_cpu_opt(self->rfx_enc, xrdp_rdp_detect_cpu()); + self->mppc_enc = mppc_enc_new(PROTO_RDP_50); + self->rfx_enc = rfx_context_new(); + rfx_context_set_cpu_opt(self->rfx_enc, xrdp_rdp_detect_cpu()); #endif - self->client_info.size = sizeof(self->client_info); - DEBUG(("out xrdp_rdp_create")); - return self; + self->client_info.size = sizeof(self->client_info); + DEBUG(("out xrdp_rdp_create")); + return self; } /*****************************************************************************/ void APP_CC -xrdp_rdp_delete(struct xrdp_rdp* self) +xrdp_rdp_delete(struct xrdp_rdp *self) { - if (self == 0) - { - return; - } - xrdp_sec_delete(self->sec_layer); + if (self == 0) + { + return; + } + + xrdp_sec_delete(self->sec_layer); #if defined(XRDP_FREERDP1) - mppc_enc_free((struct rdp_mppc_enc*)(self->mppc_enc)); - rfx_context_free((RFX_CONTEXT*)(self->rfx_enc)); + mppc_enc_free((struct rdp_mppc_enc *)(self->mppc_enc)); + rfx_context_free((RFX_CONTEXT *)(self->rfx_enc)); #endif - g_free(self); + g_free(self); } /*****************************************************************************/ int APP_CC -xrdp_rdp_init(struct xrdp_rdp* self, struct stream* s) +xrdp_rdp_init(struct xrdp_rdp *self, struct stream *s) { - if (xrdp_sec_init(self->sec_layer, s) != 0) - { - return 1; - } - s_push_layer(s, rdp_hdr, 6); - return 0; + if (xrdp_sec_init(self->sec_layer, s) != 0) + { + return 1; + } + + s_push_layer(s, rdp_hdr, 6); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_rdp_init_data(struct xrdp_rdp* self, struct stream* s) +xrdp_rdp_init_data(struct xrdp_rdp *self, struct stream *s) { - if (xrdp_sec_init(self->sec_layer, s) != 0) - { - return 1; - } - s_push_layer(s, rdp_hdr, 18); - return 0; + if (xrdp_sec_init(self->sec_layer, s) != 0) + { + return 1; + } + + s_push_layer(s, rdp_hdr, 18); + return 0; } /*****************************************************************************/ /* returns erros */ int APP_CC -xrdp_rdp_recv(struct xrdp_rdp* self, struct stream* s, int* code) +xrdp_rdp_recv(struct xrdp_rdp *self, struct stream *s, int *code) { - int error = 0; - int len = 0; - int pdu_code = 0; - int chan = 0; + int error = 0; + int len = 0; + int pdu_code = 0; + int chan = 0; - DEBUG(("in xrdp_rdp_recv")); - if (s->next_packet == 0 || s->next_packet >= s->end) - { - chan = 0; - error = xrdp_sec_recv(self->sec_layer, s, &chan); - if (error == -1) /* special code for send demand active */ + DEBUG(("in xrdp_rdp_recv")); + + if (s->next_packet == 0 || s->next_packet >= s->end) { - s->next_packet = 0; - *code = -1; - DEBUG(("out (1) xrdp_rdp_recv")); - return 0; - } - if (error != 0) - { - DEBUG(("out xrdp_rdp_recv error")); - return 1; - } - if ((chan != MCS_GLOBAL_CHANNEL) && (chan > 0)) - { - if (chan > MCS_GLOBAL_CHANNEL) - { - if(xrdp_channel_process(self->sec_layer->chan_layer, s, chan)!=0) + chan = 0; + error = xrdp_sec_recv(self->sec_layer, s, &chan); + + if (error == -1) /* special code for send demand active */ { - g_writeln("xrdp_channel_process returned unhandled error") ; + s->next_packet = 0; + *code = -1; + DEBUG(("out (1) xrdp_rdp_recv")); + return 0; } - } - else - { - g_writeln("Wrong channel Id to be handled by xrdp_channel_process %d",chan); - } - s->next_packet = 0; - *code = 0; - DEBUG(("out (2) xrdp_rdp_recv")); - return 0; - } - s->next_packet = s->p; - } - else - { - DEBUG(("xrdp_rdp_recv stream not touched")) - s->p = s->next_packet; - } - if (!s_check_rem(s, 6)) - { - s->next_packet = 0; - *code = 0; - DEBUG(("out (3) xrdp_rdp_recv")); - len = (int)(s->end - s->p); - g_writeln("xrdp_rdp_recv: bad RDP packet, length [%d]", len); - return 0; - } - else - { - in_uint16_le(s, len); - /*g_writeln("New len received : %d next packet: %d s_end: %d",len,s->next_packet,s->end); */ - in_uint16_le(s, pdu_code); - *code = pdu_code & 0xf; - in_uint8s(s, 2); /* mcs user id */ - s->next_packet += len; - DEBUG(("out (4) xrdp_rdp_recv")); - return 0; - } -} -/*****************************************************************************/ -int APP_CC -xrdp_rdp_send(struct xrdp_rdp* self, struct stream* s, int pdu_type) -{ - int len = 0; + if (error != 0) + { + DEBUG(("out xrdp_rdp_recv error")); + return 1; + } - DEBUG(("in xrdp_rdp_send")); - s_pop_layer(s, rdp_hdr); - len = s->end - s->p; - out_uint16_le(s, len); - out_uint16_le(s, 0x10 | pdu_type); - out_uint16_le(s, self->mcs_channel); - if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0) - { - DEBUG(("out xrdp_rdp_send error")); - return 1; - } - DEBUG(("out xrdp_rdp_send")); - return 0; -} + if ((chan != MCS_GLOBAL_CHANNEL) && (chan > 0)) + { + if (chan > MCS_GLOBAL_CHANNEL) + { + if (xrdp_channel_process(self->sec_layer->chan_layer, s, chan) != 0) + { + g_writeln("xrdp_channel_process returned unhandled error") ; + } + } + else + { + g_writeln("Wrong channel Id to be handled by xrdp_channel_process %d", chan); + } -/*****************************************************************************/ -int APP_CC -xrdp_rdp_send_data(struct xrdp_rdp* self, struct stream* s, - int data_pdu_type) -{ - int len; - int ctype; - int clen; - int dlen; - int pdulen; - int pdutype; - int tocomplen; - int iso_offset; - int mcs_offset; - int sec_offset; - int rdp_offset; - struct stream ls; -#if defined(XRDP_FREERDP1) - struct rdp_mppc_enc* mppc_enc; -#endif + s->next_packet = 0; + *code = 0; + DEBUG(("out (2) xrdp_rdp_recv")); + return 0; + } - DEBUG(("in xrdp_rdp_send_data")); - s_pop_layer(s, rdp_hdr); - len = (int)(s->end - s->p); - pdutype = 0x10 | RDP_PDU_DATA; - pdulen = len; - dlen = len; - ctype = 0; - clen = len; - tocomplen = pdulen - 18; -#if defined(XRDP_FREERDP1) - if (self->client_info.rdp_compression && self->session->up_and_running) - { - mppc_enc = (struct rdp_mppc_enc*)(self->mppc_enc); - if (compress_rdp(mppc_enc, (tui8*)(s->p + 18), tocomplen)) - { - DEBUG(("mppc_encode ok flags 0x%x bytes_in_opb %d historyOffset %d " - "tocomplen %d", mppc_enc->flags, mppc_enc->bytes_in_opb, - mppc_enc->historyOffset, tocomplen)); - if (mppc_enc->flags & RDP_MPPC_COMPRESSED) - { - clen = mppc_enc->bytes_in_opb + 18; - pdulen = clen; - ctype = mppc_enc->flags; - iso_offset = (int)(s->iso_hdr - s->data); - mcs_offset = (int)(s->mcs_hdr - s->data); - sec_offset = (int)(s->sec_hdr - s->data); - rdp_offset = (int)(s->rdp_hdr - s->data); - - /* outputBuffer has 64 bytes preceding it */ - ls.data = mppc_enc->outputBuffer - (rdp_offset + 18); - ls.p = ls.data + rdp_offset; - ls.end = ls.p + clen; - ls.size = clen; - ls.iso_hdr = ls.data + iso_offset; - ls.mcs_hdr = ls.data + mcs_offset; - ls.sec_hdr = ls.data + sec_offset; - ls.rdp_hdr = ls.data + rdp_offset; - ls.channel_hdr = 0; - ls.next_packet = 0; - s = &ls; - } + s->next_packet = s->p; } else { - g_writeln("mppc_encode not ok"); + DEBUG(("xrdp_rdp_recv stream not touched")) + s->p = s->next_packet; } - } -#endif - out_uint16_le(s, pdulen); - out_uint16_le(s, pdutype); - out_uint16_le(s, self->mcs_channel); - out_uint32_le(s, self->share_id); - out_uint8(s, 0); - out_uint8(s, 1); - out_uint16_le(s, dlen); - out_uint8(s, data_pdu_type); - out_uint8(s, ctype); - out_uint16_le(s, clen); - if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0) - { - DEBUG(("out xrdp_rdp_send_data error")); - return 1; - } - DEBUG(("out xrdp_rdp_send_data")); - return 0; + if (!s_check_rem(s, 6)) + { + s->next_packet = 0; + *code = 0; + DEBUG(("out (3) xrdp_rdp_recv")); + len = (int)(s->end - s->p); + g_writeln("xrdp_rdp_recv: bad RDP packet, length [%d]", len); + return 0; + } + else + { + in_uint16_le(s, len); + /*g_writeln("New len received : %d next packet: %d s_end: %d",len,s->next_packet,s->end); */ + in_uint16_le(s, pdu_code); + *code = pdu_code & 0xf; + in_uint8s(s, 2); /* mcs user id */ + s->next_packet += len; + DEBUG(("out (4) xrdp_rdp_recv")); + return 0; + } } /*****************************************************************************/ int APP_CC -xrdp_rdp_send_data_update_sync(struct xrdp_rdp* self) +xrdp_rdp_send(struct xrdp_rdp *self, struct stream *s, int pdu_type) { - struct stream * s = (struct stream *)NULL; + int len = 0; - make_stream(s); - init_stream(s, 8192); - DEBUG(("in xrdp_rdp_send_data_update_sync")); - if (xrdp_rdp_init_data(self, s) != 0) - { - DEBUG(("out xrdp_rdp_send_data_update_sync error")); + DEBUG(("in xrdp_rdp_send")); + s_pop_layer(s, rdp_hdr); + len = s->end - s->p; + out_uint16_le(s, len); + out_uint16_le(s, 0x10 | pdu_type); + out_uint16_le(s, self->mcs_channel); + + if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0) + { + DEBUG(("out xrdp_rdp_send error")); + return 1; + } + + DEBUG(("out xrdp_rdp_send")); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, + int data_pdu_type) +{ + int len; + int ctype; + int clen; + int dlen; + int pdulen; + int pdutype; + int tocomplen; + int iso_offset; + int mcs_offset; + int sec_offset; + int rdp_offset; + struct stream ls; +#if defined(XRDP_FREERDP1) + struct rdp_mppc_enc *mppc_enc; +#endif + + DEBUG(("in xrdp_rdp_send_data")); + s_pop_layer(s, rdp_hdr); + len = (int)(s->end - s->p); + pdutype = 0x10 | RDP_PDU_DATA; + pdulen = len; + dlen = len; + ctype = 0; + clen = len; + tocomplen = pdulen - 18; +#if defined(XRDP_FREERDP1) + + if (self->client_info.rdp_compression && self->session->up_and_running) + { + mppc_enc = (struct rdp_mppc_enc *)(self->mppc_enc); + + if (compress_rdp(mppc_enc, (tui8 *)(s->p + 18), tocomplen)) + { + DEBUG(("mppc_encode ok flags 0x%x bytes_in_opb %d historyOffset %d " + "tocomplen %d", mppc_enc->flags, mppc_enc->bytes_in_opb, + mppc_enc->historyOffset, tocomplen)); + + if (mppc_enc->flags & RDP_MPPC_COMPRESSED) + { + clen = mppc_enc->bytes_in_opb + 18; + pdulen = clen; + ctype = mppc_enc->flags; + iso_offset = (int)(s->iso_hdr - s->data); + mcs_offset = (int)(s->mcs_hdr - s->data); + sec_offset = (int)(s->sec_hdr - s->data); + rdp_offset = (int)(s->rdp_hdr - s->data); + + /* outputBuffer has 64 bytes preceding it */ + ls.data = mppc_enc->outputBuffer - (rdp_offset + 18); + ls.p = ls.data + rdp_offset; + ls.end = ls.p + clen; + ls.size = clen; + ls.iso_hdr = ls.data + iso_offset; + ls.mcs_hdr = ls.data + mcs_offset; + ls.sec_hdr = ls.data + sec_offset; + ls.rdp_hdr = ls.data + rdp_offset; + ls.channel_hdr = 0; + ls.next_packet = 0; + s = &ls; + } + } + else + { + g_writeln("mppc_encode not ok"); + } + } + +#endif + out_uint16_le(s, pdulen); + out_uint16_le(s, pdutype); + out_uint16_le(s, self->mcs_channel); + out_uint32_le(s, self->share_id); + out_uint8(s, 0); + out_uint8(s, 1); + out_uint16_le(s, dlen); + out_uint8(s, data_pdu_type); + out_uint8(s, ctype); + out_uint16_le(s, clen); + + if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0) + { + DEBUG(("out xrdp_rdp_send_data error")); + return 1; + } + + DEBUG(("out xrdp_rdp_send_data")); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_rdp_send_data_update_sync(struct xrdp_rdp *self) +{ + struct stream *s = (struct stream *)NULL; + + make_stream(s); + init_stream(s, 8192); + DEBUG(("in xrdp_rdp_send_data_update_sync")); + + if (xrdp_rdp_init_data(self, s) != 0) + { + DEBUG(("out xrdp_rdp_send_data_update_sync error")); + free_stream(s); + return 1; + } + + out_uint16_le(s, RDP_UPDATE_SYNCHRONIZE); + out_uint8s(s, 2); + s_mark_end(s); + + if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_UPDATE) != 0) + { + DEBUG(("out xrdp_rdp_send_data_update_sync error")); + free_stream(s); + return 1; + } + + DEBUG(("out xrdp_rdp_send_data_update_sync")); free_stream(s); - return 1; - } - out_uint16_le(s, RDP_UPDATE_SYNCHRONIZE); - out_uint8s(s, 2); - s_mark_end(s); - if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_UPDATE) != 0) - { - DEBUG(("out xrdp_rdp_send_data_update_sync error")); - free_stream(s); - return 1; - } - DEBUG(("out xrdp_rdp_send_data_update_sync")); - free_stream(s); - return 0; + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_rdp_parse_client_mcs_data(struct xrdp_rdp* self) +xrdp_rdp_parse_client_mcs_data(struct xrdp_rdp *self) { - struct stream* p = (struct stream *)NULL; - int i = 0; + struct stream *p = (struct stream *)NULL; + int i = 0; - p = &(self->sec_layer->client_mcs_data); - p->p = p->data; - in_uint8s(p, 31); - in_uint16_le(p, self->client_info.width); - in_uint16_le(p, self->client_info.height); - in_uint8s(p, 120); - self->client_info.bpp = 8; - in_uint16_le(p, i); - switch (i) - { - case 0xca01: - in_uint8s(p, 6); - in_uint8(p, i); - if (i > 8) - { - self->client_info.bpp = i; - } - break; - case 0xca02: - self->client_info.bpp = 15; - break; - case 0xca03: - self->client_info.bpp = 16; - break; - case 0xca04: - self->client_info.bpp = 24; - break; - } - if (self->client_info.max_bpp > 0) - { - if (self->client_info.bpp > self->client_info.max_bpp) + p = &(self->sec_layer->client_mcs_data); + p->p = p->data; + in_uint8s(p, 31); + in_uint16_le(p, self->client_info.width); + in_uint16_le(p, self->client_info.height); + in_uint8s(p, 120); + self->client_info.bpp = 8; + in_uint16_le(p, i); + + switch (i) { - self->client_info.bpp = self->client_info.max_bpp; + case 0xca01: + in_uint8s(p, 6); + in_uint8(p, i); + + if (i > 8) + { + self->client_info.bpp = i; + } + + break; + case 0xca02: + self->client_info.bpp = 15; + break; + case 0xca03: + self->client_info.bpp = 16; + break; + case 0xca04: + self->client_info.bpp = 24; + break; } - } - p->p = p->data; - DEBUG(("client width %d, client height %d bpp %d", - self->client_info.width, self->client_info.height, - self->client_info.bpp)); - return 0; + + if (self->client_info.max_bpp > 0) + { + if (self->client_info.bpp > self->client_info.max_bpp) + { + self->client_info.bpp = self->client_info.max_bpp; + } + } + + p->p = p->data; + DEBUG(("client width %d, client height %d bpp %d", + self->client_info.width, self->client_info.height, + self->client_info.bpp)); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_rdp_incoming(struct xrdp_rdp* self) +xrdp_rdp_incoming(struct xrdp_rdp *self) { - DEBUG(("in xrdp_rdp_incoming")); - if (xrdp_sec_incoming(self->sec_layer) != 0) - { - return 1; - } - self->mcs_channel = self->sec_layer->mcs_layer->userid + - MCS_USERCHANNEL_BASE; - xrdp_rdp_parse_client_mcs_data(self); - DEBUG(("out xrdp_rdp_incoming mcs channel %d", self->mcs_channel)); - return 0; + DEBUG(("in xrdp_rdp_incoming")); + + if (xrdp_sec_incoming(self->sec_layer) != 0) + { + return 1; + } + + self->mcs_channel = self->sec_layer->mcs_layer->userid + + MCS_USERCHANNEL_BASE; + xrdp_rdp_parse_client_mcs_data(self); + DEBUG(("out xrdp_rdp_incoming mcs channel %d", self->mcs_channel)); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_rdp_send_demand_active(struct xrdp_rdp* self) +xrdp_rdp_send_demand_active(struct xrdp_rdp *self) { - struct stream* s; - int caps_count; - int caps_size; - int codec_caps_count; - int codec_caps_size; - char* caps_count_ptr; - char* caps_size_ptr; - char* caps_ptr; - char* codec_caps_count_ptr; - char* codec_caps_size_ptr; + struct stream *s; + int caps_count; + int caps_size; + int codec_caps_count; + int codec_caps_size; + char *caps_count_ptr; + char *caps_size_ptr; + char *caps_ptr; + char *codec_caps_count_ptr; + char *codec_caps_size_ptr; - make_stream(s); - init_stream(s, 8192); - if (xrdp_rdp_init(self, s) != 0) - { - free_stream(s); - return 1; - } + make_stream(s); + init_stream(s, 8192); - caps_count = 0; - out_uint32_le(s, self->share_id); - out_uint16_le(s, 4); /* 4 chars for RDP\0 */ - /* 2 bytes size after num caps, set later */ - caps_size_ptr = s->p; - out_uint8s(s, 2); - out_uint8a(s, "RDP", 4); - /* 4 byte num caps, set later */ - caps_count_ptr = s->p; - out_uint8s(s, 4); - caps_ptr = s->p; + if (xrdp_rdp_init(self, s) != 0) + { + free_stream(s); + return 1; + } - /* Output share capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_SHARE); - out_uint16_le(s, RDP_CAPLEN_SHARE); - out_uint16_le(s, self->mcs_channel); - out_uint16_be(s, 0xb5e2); /* 0x73e1 */ + caps_count = 0; + out_uint32_le(s, self->share_id); + out_uint16_le(s, 4); /* 4 chars for RDP\0 */ + /* 2 bytes size after num caps, set later */ + caps_size_ptr = s->p; + out_uint8s(s, 2); + out_uint8a(s, "RDP", 4); + /* 4 byte num caps, set later */ + caps_count_ptr = s->p; + out_uint8s(s, 4); + caps_ptr = s->p; - /* Output general capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_GENERAL); /* 1 */ - out_uint16_le(s, RDP_CAPLEN_GENERAL); /* 24(0x18) */ - 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_le(s, 0); /* pad */ - out_uint16_le(s, 0); /* Compression types */ - //out_uint16_le(s, 0); /* pad use 0x40d for rdp packets, 0 for not */ - out_uint16_le(s, 0x40d); /* pad use 0x40d for rdp packets, 0 for not */ - out_uint16_le(s, 0); /* Update capability */ - out_uint16_le(s, 0); /* Remote unshare capability */ - out_uint16_le(s, 0); /* Compression level */ - out_uint16_le(s, 0); /* Pad */ + /* Output share capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_SHARE); + out_uint16_le(s, RDP_CAPLEN_SHARE); + out_uint16_le(s, self->mcs_channel); + out_uint16_be(s, 0xb5e2); /* 0x73e1 */ - /* Output bitmap capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_BITMAP); /* 2 */ - out_uint16_le(s, RDP_CAPLEN_BITMAP); /* 28(0x1c) */ - out_uint16_le(s, self->client_info.bpp); /* Preferred BPP */ - 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, self->client_info.width); /* width */ - out_uint16_le(s, self->client_info.height); /* height */ - out_uint16_le(s, 0); /* Pad */ - out_uint16_le(s, 1); /* Allow resize */ - out_uint16_le(s, 1); /* bitmap compression */ - out_uint16_le(s, 0); /* unknown */ - out_uint16_le(s, 0); /* unknown */ - out_uint16_le(s, 0); /* pad */ + /* Output general capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_GENERAL); /* 1 */ + out_uint16_le(s, RDP_CAPLEN_GENERAL); /* 24(0x18) */ + 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_le(s, 0); /* pad */ + out_uint16_le(s, 0); /* Compression types */ + //out_uint16_le(s, 0); /* pad use 0x40d for rdp packets, 0 for not */ + out_uint16_le(s, 0x40d); /* pad use 0x40d for rdp packets, 0 for not */ + out_uint16_le(s, 0); /* Update capability */ + out_uint16_le(s, 0); /* Remote unshare capability */ + out_uint16_le(s, 0); /* Compression level */ + out_uint16_le(s, 0); /* Pad */ - /* Output font capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_FONT); /* 14 */ - out_uint16_le(s, RDP_CAPLEN_FONT); /* 4 */ + /* Output bitmap capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_BITMAP); /* 2 */ + out_uint16_le(s, RDP_CAPLEN_BITMAP); /* 28(0x1c) */ + out_uint16_le(s, self->client_info.bpp); /* Preferred BPP */ + 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, self->client_info.width); /* width */ + out_uint16_le(s, self->client_info.height); /* height */ + out_uint16_le(s, 0); /* Pad */ + out_uint16_le(s, 1); /* Allow resize */ + out_uint16_le(s, 1); /* bitmap compression */ + out_uint16_le(s, 0); /* unknown */ + out_uint16_le(s, 0); /* unknown */ + out_uint16_le(s, 0); /* pad */ - /* Output order capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_ORDER); /* 3 */ - out_uint16_le(s, RDP_CAPLEN_ORDER); /* 88(0x58) */ - out_uint8s(s, 16); - out_uint32_be(s, 0x40420f00); - out_uint16_le(s, 1); /* Cache X granularity */ - out_uint16_le(s, 20); /* Cache Y granularity */ - out_uint16_le(s, 0); /* Pad */ - out_uint16_le(s, 1); /* Max order level */ - out_uint16_le(s, 0x2f); /* Number of fonts */ - out_uint16_le(s, 0x22); /* Capability flags */ - /* caps */ - out_uint8(s, 1); /* dest blt */ - out_uint8(s, 1); /* pat blt */ - out_uint8(s, 1); /* screen blt */ - out_uint8(s, 1); /* mem blt */ - out_uint8(s, 0); /* tri blt */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* nine grid */ - out_uint8(s, 1); /* line to */ - out_uint8(s, 0); /* multi nine grid */ - out_uint8(s, 1); /* rect */ - out_uint8(s, 0); /* desk save */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* multi dest blt */ - out_uint8(s, 0); /* multi pat blt */ - out_uint8(s, 0); /* multi screen blt */ - out_uint8(s, 1); /* multi rect */ - out_uint8(s, 0); /* fast index */ - out_uint8(s, 0); /* polygonSC ([MS-RDPEGDI], 2.2.2.2.1.1.2.16) */ - out_uint8(s, 0); /* polygonCB ([MS-RDPEGDI], 2.2.2.2.1.1.2.17) */ - out_uint8(s, 0); /* polyline */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* fast glyph */ - out_uint8(s, 0); /* ellipse */ - out_uint8(s, 0); /* ellipse */ - out_uint8(s, 0); /* ? */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint8(s, 0); /* unused */ - out_uint16_le(s, 0x6a1); - /* declare support of bitmap cache rev3 */ - out_uint16_le(s, XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT); - out_uint32_le(s, 0x0f4240); /* desk save */ - out_uint32_le(s, 0x0f4240); /* desk save */ - out_uint32_le(s, 1); /* ? */ - out_uint32_le(s, 0); /* ? */ + /* Output font capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_FONT); /* 14 */ + out_uint16_le(s, RDP_CAPLEN_FONT); /* 4 */ - /* Output bmpcodecs capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_BMPCODECS); - codec_caps_size_ptr = s->p; - out_uint8s(s, 2); /* cap len set later */ - codec_caps_count = 0; - codec_caps_count_ptr = s->p; - out_uint8s(s, 1); /* bitmapCodecCount set later */ - /* nscodec */ - codec_caps_count++; - out_uint8a(s, XR_CODEC_GUID_NSCODEC, 16); - out_uint8(s, 1); /* codec id, must be 1 */ - out_uint16_le(s, 3); - out_uint8(s, 0x01); /* fAllowDynamicFidelity */ - out_uint8(s, 0x01); /* fAllowSubsampling */ - out_uint8(s, 0x03); /* colorLossLevel */ - /* remotefx */ - codec_caps_count++; - out_uint8a(s, XR_CODEC_GUID_REMOTEFX, 16); - out_uint8(s, 0); /* codec id, client sets */ - out_uint16_le(s, 256); - out_uint8s(s, 256); - /* jpeg */ - codec_caps_count++; - out_uint8a(s, XR_CODEC_GUID_JPEG, 16); - out_uint8(s, 0); /* codec id, client sets */ - out_uint16_le(s, 1); /* ext length */ - out_uint8(s, 75); - /* calculate and set size and count */ - codec_caps_size = (int)(s->p - codec_caps_size_ptr); - codec_caps_size += 2; /* 2 bytes for RDP_CAPSET_BMPCODECS above */ - codec_caps_size_ptr[0] = codec_caps_size; - codec_caps_size_ptr[1] = codec_caps_size >> 8; - codec_caps_count_ptr[0] = codec_caps_count; + /* Output order capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_ORDER); /* 3 */ + out_uint16_le(s, RDP_CAPLEN_ORDER); /* 88(0x58) */ + out_uint8s(s, 16); + out_uint32_be(s, 0x40420f00); + out_uint16_le(s, 1); /* Cache X granularity */ + out_uint16_le(s, 20); /* Cache Y granularity */ + out_uint16_le(s, 0); /* Pad */ + out_uint16_le(s, 1); /* Max order level */ + out_uint16_le(s, 0x2f); /* Number of fonts */ + out_uint16_le(s, 0x22); /* Capability flags */ + /* caps */ + out_uint8(s, 1); /* dest blt */ + out_uint8(s, 1); /* pat blt */ + out_uint8(s, 1); /* screen blt */ + out_uint8(s, 1); /* mem blt */ + out_uint8(s, 0); /* tri blt */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* nine grid */ + out_uint8(s, 1); /* line to */ + out_uint8(s, 0); /* multi nine grid */ + out_uint8(s, 1); /* rect */ + out_uint8(s, 0); /* desk save */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* multi dest blt */ + out_uint8(s, 0); /* multi pat blt */ + out_uint8(s, 0); /* multi screen blt */ + out_uint8(s, 1); /* multi rect */ + out_uint8(s, 0); /* fast index */ + out_uint8(s, 0); /* polygonSC ([MS-RDPEGDI], 2.2.2.2.1.1.2.16) */ + out_uint8(s, 0); /* polygonCB ([MS-RDPEGDI], 2.2.2.2.1.1.2.17) */ + out_uint8(s, 0); /* polyline */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* fast glyph */ + out_uint8(s, 0); /* ellipse */ + out_uint8(s, 0); /* ellipse */ + out_uint8(s, 0); /* ? */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* unused */ + out_uint8(s, 0); /* unused */ + out_uint16_le(s, 0x6a1); + /* declare support of bitmap cache rev3 */ + out_uint16_le(s, XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT); + out_uint32_le(s, 0x0f4240); /* desk save */ + out_uint32_le(s, 0x0f4240); /* desk save */ + out_uint32_le(s, 1); /* ? */ + out_uint32_le(s, 0); /* ? */ - /* Output color cache capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_COLCACHE); - out_uint16_le(s, RDP_CAPLEN_COLCACHE); - out_uint16_le(s, 6); /* cache size */ - out_uint16_le(s, 0); /* pad */ + /* Output bmpcodecs capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_BMPCODECS); + codec_caps_size_ptr = s->p; + out_uint8s(s, 2); /* cap len set later */ + codec_caps_count = 0; + codec_caps_count_ptr = s->p; + out_uint8s(s, 1); /* bitmapCodecCount set later */ + /* nscodec */ + codec_caps_count++; + out_uint8a(s, XR_CODEC_GUID_NSCODEC, 16); + out_uint8(s, 1); /* codec id, must be 1 */ + out_uint16_le(s, 3); + out_uint8(s, 0x01); /* fAllowDynamicFidelity */ + out_uint8(s, 0x01); /* fAllowSubsampling */ + out_uint8(s, 0x03); /* colorLossLevel */ + /* remotefx */ + codec_caps_count++; + out_uint8a(s, XR_CODEC_GUID_REMOTEFX, 16); + out_uint8(s, 0); /* codec id, client sets */ + out_uint16_le(s, 256); + out_uint8s(s, 256); + /* jpeg */ + codec_caps_count++; + out_uint8a(s, XR_CODEC_GUID_JPEG, 16); + out_uint8(s, 0); /* codec id, client sets */ + out_uint16_le(s, 1); /* ext length */ + out_uint8(s, 75); + /* calculate and set size and count */ + codec_caps_size = (int)(s->p - codec_caps_size_ptr); + codec_caps_size += 2; /* 2 bytes for RDP_CAPSET_BMPCODECS above */ + codec_caps_size_ptr[0] = codec_caps_size; + codec_caps_size_ptr[1] = codec_caps_size >> 8; + codec_caps_count_ptr[0] = codec_caps_count; - /* Output pointer capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_POINTER); - out_uint16_le(s, RDP_CAPLEN_POINTER); - out_uint16_le(s, 1); /* Colour pointer */ - out_uint16_le(s, 0x19); /* Cache size */ - out_uint16_le(s, 0x19); /* Cache size */ + /* Output color cache capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_COLCACHE); + out_uint16_le(s, RDP_CAPLEN_COLCACHE); + out_uint16_le(s, 6); /* cache size */ + out_uint16_le(s, 0); /* pad */ - /* Output input capability set */ - caps_count++; - out_uint16_le(s, RDP_CAPSET_INPUT); /* 13(0xd) */ - out_uint16_le(s, RDP_CAPLEN_INPUT); /* 88(0x58) */ - out_uint8(s, 1); - out_uint8s(s, 83); + /* Output pointer capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_POINTER); + out_uint16_le(s, RDP_CAPLEN_POINTER); + out_uint16_le(s, 1); /* Colour pointer */ + out_uint16_le(s, 0x19); /* Cache size */ + out_uint16_le(s, 0x19); /* Cache size */ - /* Remote Programs Capability Set */ - caps_count++; - out_uint16_le(s, 0x0017); /* CAPSETTYPE_RAIL */ - out_uint16_le(s, 8); - out_uint32_le(s, 3); /* TS_RAIL_LEVEL_SUPPORTED + /* Output input capability set */ + caps_count++; + out_uint16_le(s, RDP_CAPSET_INPUT); /* 13(0xd) */ + out_uint16_le(s, RDP_CAPLEN_INPUT); /* 88(0x58) */ + out_uint8(s, 1); + out_uint8s(s, 83); + + /* Remote Programs Capability Set */ + caps_count++; + out_uint16_le(s, 0x0017); /* CAPSETTYPE_RAIL */ + out_uint16_le(s, 8); + out_uint32_le(s, 3); /* TS_RAIL_LEVEL_SUPPORTED TS_RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED */ - /* Window List Capability Set */ - caps_count++; - out_uint16_le(s, 0x0018); /* CAPSETTYPE_WINDOW */ - out_uint16_le(s, 11); - out_uint32_le(s, 2); /* TS_WINDOW_LEVEL_SUPPORTED_EX */ - out_uint8(s, 3); /* NumIconCaches */ - out_uint16_le(s, 12); /* NumIconCacheEntries */ + /* Window List Capability Set */ + caps_count++; + out_uint16_le(s, 0x0018); /* CAPSETTYPE_WINDOW */ + out_uint16_le(s, 11); + out_uint32_le(s, 2); /* TS_WINDOW_LEVEL_SUPPORTED_EX */ + out_uint8(s, 3); /* NumIconCaches */ + out_uint16_le(s, 12); /* NumIconCacheEntries */ - /* 6 - bitmap cache v3 codecid */ - caps_count++; - out_uint16_le(s, 0x0006); - out_uint16_le(s, 5); - out_uint8(s, 0); /* client sets */ + /* 6 - bitmap cache v3 codecid */ + caps_count++; + out_uint16_le(s, 0x0006); + out_uint16_le(s, 5); + out_uint8(s, 0); /* client sets */ - out_uint8s(s, 4); /* pad */ + out_uint8s(s, 4); /* pad */ - s_mark_end(s); + s_mark_end(s); - caps_size = (int)(s->end - caps_ptr); - caps_size_ptr[0] = caps_size; - caps_size_ptr[1] = caps_size >> 8; + caps_size = (int)(s->end - caps_ptr); + caps_size_ptr[0] = caps_size; + caps_size_ptr[1] = caps_size >> 8; - caps_count_ptr[0] = caps_count; - caps_count_ptr[1] = caps_count >> 8; - caps_count_ptr[2] = caps_count >> 16; - caps_count_ptr[3] = caps_count >> 24; + caps_count_ptr[0] = caps_count; + caps_count_ptr[1] = caps_count >> 8; + caps_count_ptr[2] = caps_count >> 16; + caps_count_ptr[3] = caps_count >> 24; + + if (xrdp_rdp_send(self, s, RDP_PDU_DEMAND_ACTIVE) != 0) + { + free_stream(s); + return 1; + } - if (xrdp_rdp_send(self, s, RDP_PDU_DEMAND_ACTIVE) != 0) - { free_stream(s); - return 1; - } - - free_stream(s); - return 0; + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_process_capset_general(struct xrdp_rdp* self, struct stream* s, +xrdp_process_capset_general(struct xrdp_rdp *self, struct stream *s, int len) { - int i; + int i; - in_uint8s(s, 10); - in_uint16_le(s, i); - /* use_compact_packets is pretty much 'use rdp5' */ - self->client_info.use_compact_packets = (i != 0); - /* op2 is a boolean to use compact bitmap headers in bitmap cache */ - /* set it to same as 'use rdp5' boolean */ - self->client_info.op2 = self->client_info.use_compact_packets; - return 0; + in_uint8s(s, 10); + in_uint16_le(s, i); + /* use_compact_packets is pretty much 'use rdp5' */ + self->client_info.use_compact_packets = (i != 0); + /* op2 is a boolean to use compact bitmap headers in bitmap cache */ + /* set it to same as 'use rdp5' boolean */ + self->client_info.op2 = self->client_info.use_compact_packets; + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_process_capset_order(struct xrdp_rdp* self, struct stream* s, +xrdp_process_capset_order(struct xrdp_rdp *self, struct stream *s, int len) { - int i; - char order_caps[32]; - int ex_flags; + int i; + char order_caps[32]; + int ex_flags; - DEBUG(("order capabilities")); - in_uint8s(s, 20); /* Terminal desc, pad */ - in_uint8s(s, 2); /* Cache X granularity */ - in_uint8s(s, 2); /* Cache Y granularity */ - in_uint8s(s, 2); /* Pad */ - in_uint8s(s, 2); /* Max order level */ - in_uint8s(s, 2); /* Number of fonts */ - in_uint8s(s, 2); /* Capability flags */ - in_uint8a(s, order_caps, 32); /* Orders supported */ - DEBUG(("dest blt-0 %d", order_caps[0])); - DEBUG(("pat blt-1 %d", order_caps[1])); - DEBUG(("screen blt-2 %d", order_caps[2])); - DEBUG(("memblt-3-13 %d %d", order_caps[3], order_caps[13])); - DEBUG(("triblt-4-14 %d %d", order_caps[4], order_caps[14])); - DEBUG(("line-8 %d", order_caps[8])); - DEBUG(("line-9 %d", order_caps[9])); - DEBUG(("rect-10 %d", order_caps[10])); - DEBUG(("desksave-11 %d", order_caps[11])); - DEBUG(("polygon-20 %d", order_caps[20])); - DEBUG(("polygon2-21 %d", order_caps[21])); - DEBUG(("polyline-22 %d", order_caps[22])); - DEBUG(("ellipse-25 %d", order_caps[25])); - DEBUG(("ellipse2-26 %d", order_caps[26])); - DEBUG(("text2-27 %d", order_caps[27])); - DEBUG(("order_caps dump")); + DEBUG(("order capabilities")); + in_uint8s(s, 20); /* Terminal desc, pad */ + in_uint8s(s, 2); /* Cache X granularity */ + in_uint8s(s, 2); /* Cache Y granularity */ + in_uint8s(s, 2); /* Pad */ + in_uint8s(s, 2); /* Max order level */ + in_uint8s(s, 2); /* Number of fonts */ + in_uint8s(s, 2); /* Capability flags */ + in_uint8a(s, order_caps, 32); /* Orders supported */ + DEBUG(("dest blt-0 %d", order_caps[0])); + DEBUG(("pat blt-1 %d", order_caps[1])); + DEBUG(("screen blt-2 %d", order_caps[2])); + DEBUG(("memblt-3-13 %d %d", order_caps[3], order_caps[13])); + DEBUG(("triblt-4-14 %d %d", order_caps[4], order_caps[14])); + DEBUG(("line-8 %d", order_caps[8])); + DEBUG(("line-9 %d", order_caps[9])); + DEBUG(("rect-10 %d", order_caps[10])); + DEBUG(("desksave-11 %d", order_caps[11])); + DEBUG(("polygon-20 %d", order_caps[20])); + DEBUG(("polygon2-21 %d", order_caps[21])); + DEBUG(("polyline-22 %d", order_caps[22])); + DEBUG(("ellipse-25 %d", order_caps[25])); + DEBUG(("ellipse2-26 %d", order_caps[26])); + DEBUG(("text2-27 %d", order_caps[27])); + DEBUG(("order_caps dump")); #if defined(XRDP_DEBUG) - g_hexdump(order_caps, 32); + g_hexdump(order_caps, 32); #endif - in_uint8s(s, 2); /* Text capability flags */ - /* read extended order support flags */ - in_uint16_le(s, ex_flags); /* Ex flags */ - if (ex_flags & XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT) - { - g_writeln("xrdp_process_capset_order: bitmap cache v3 supported"); - self->client_info.bitmap_cache_version |= 4; - } - in_uint8s(s, 4); /* Pad */ + in_uint8s(s, 2); /* Text capability flags */ + /* read extended order support flags */ + in_uint16_le(s, ex_flags); /* Ex flags */ - in_uint32_le(s, i); /* desktop cache size, usually 0x38400 */ - self->client_info.desktop_cache = i; - DEBUG(("desktop cache size %d", i)); - in_uint8s(s, 4); /* Unknown */ - in_uint8s(s, 4); /* Unknown */ - return 0; + if (ex_flags & XR_ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT) + { + g_writeln("xrdp_process_capset_order: bitmap cache v3 supported"); + self->client_info.bitmap_cache_version |= 4; + } + + in_uint8s(s, 4); /* Pad */ + + in_uint32_le(s, i); /* desktop cache size, usually 0x38400 */ + self->client_info.desktop_cache = i; + DEBUG(("desktop cache size %d", i)); + in_uint8s(s, 4); /* Unknown */ + in_uint8s(s, 4); /* Unknown */ + return 0; } /*****************************************************************************/ /* get the bitmap cache size */ static int APP_CC -xrdp_process_capset_bmpcache(struct xrdp_rdp* self, struct stream* s, +xrdp_process_capset_bmpcache(struct xrdp_rdp *self, struct stream *s, int len) { - self->client_info.bitmap_cache_version |= 1; - in_uint8s(s, 24); - in_uint16_le(s, self->client_info.cache1_entries); - in_uint16_le(s, self->client_info.cache1_size); - in_uint16_le(s, self->client_info.cache2_entries); - in_uint16_le(s, self->client_info.cache2_size); - in_uint16_le(s, self->client_info.cache3_entries); - in_uint16_le(s, self->client_info.cache3_size); - DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, - self->client_info.cache1_size)); - DEBUG(("cache2 entries %d size %d", self->client_info.cache2_entries, - self->client_info.cache2_size)); - DEBUG(("cache3 entries %d size %d", self->client_info.cache3_entries, - self->client_info.cache3_size)); - return 0; + self->client_info.bitmap_cache_version |= 1; + in_uint8s(s, 24); + in_uint16_le(s, self->client_info.cache1_entries); + in_uint16_le(s, self->client_info.cache1_size); + in_uint16_le(s, self->client_info.cache2_entries); + in_uint16_le(s, self->client_info.cache2_size); + in_uint16_le(s, self->client_info.cache3_entries); + in_uint16_le(s, self->client_info.cache3_size); + DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, + self->client_info.cache1_size)); + DEBUG(("cache2 entries %d size %d", self->client_info.cache2_entries, + self->client_info.cache2_size)); + DEBUG(("cache3 entries %d size %d", self->client_info.cache3_entries, + self->client_info.cache3_size)); + return 0; } /*****************************************************************************/ /* get the bitmap cache size */ static int APP_CC -xrdp_process_capset_bmpcache2(struct xrdp_rdp* self, struct stream* s, +xrdp_process_capset_bmpcache2(struct xrdp_rdp *self, struct stream *s, int len) { - int Bpp = 0; - int i = 0; + int Bpp = 0; + int i = 0; - self->client_info.bitmap_cache_version |= 2; - Bpp = (self->client_info.bpp + 7) / 8; - in_uint16_le(s, i); /* cache flags */ - self->client_info.bitmap_cache_persist_enable = i; - in_uint8s(s, 2); /* number of caches in set, 3 */ - in_uint32_le(s, i); - i = MIN(i, 2000); - self->client_info.cache1_entries = i; - self->client_info.cache1_size = 256 * Bpp; - in_uint32_le(s, i); - i = MIN(i, 2000); - self->client_info.cache2_entries = i; - self->client_info.cache2_size = 1024 * Bpp; - in_uint32_le(s, i); - i = i & 0x7fffffff; - i = MIN(i, 2000); - self->client_info.cache3_entries = i; - self->client_info.cache3_size = 4096 * Bpp; - DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, - self->client_info.cache1_size)); - DEBUG(("cache2 entries %d size %d", self->client_info.cache2_entries, - self->client_info.cache2_size)); - DEBUG(("cache3 entries %d size %d", self->client_info.cache3_entries, - self->client_info.cache3_size)); - return 0; + self->client_info.bitmap_cache_version |= 2; + Bpp = (self->client_info.bpp + 7) / 8; + in_uint16_le(s, i); /* cache flags */ + self->client_info.bitmap_cache_persist_enable = i; + in_uint8s(s, 2); /* number of caches in set, 3 */ + in_uint32_le(s, i); + i = MIN(i, 2000); + self->client_info.cache1_entries = i; + self->client_info.cache1_size = 256 * Bpp; + in_uint32_le(s, i); + i = MIN(i, 2000); + self->client_info.cache2_entries = i; + self->client_info.cache2_size = 1024 * Bpp; + in_uint32_le(s, i); + i = i & 0x7fffffff; + i = MIN(i, 2000); + self->client_info.cache3_entries = i; + self->client_info.cache3_size = 4096 * Bpp; + DEBUG(("cache1 entries %d size %d", self->client_info.cache1_entries, + self->client_info.cache1_size)); + DEBUG(("cache2 entries %d size %d", self->client_info.cache2_entries, + self->client_info.cache2_size)); + DEBUG(("cache3 entries %d size %d", self->client_info.cache3_entries, + self->client_info.cache3_size)); + return 0; } /*****************************************************************************/ static int -xrdp_process_capset_cache_v3_codec_id(struct xrdp_rdp* self, struct stream* s, +xrdp_process_capset_cache_v3_codec_id(struct xrdp_rdp *self, struct stream *s, int len) { - int codec_id; + int codec_id; - in_uint8(s, codec_id); - g_writeln("xrdp_process_capset_cache_v3_codec_id: cache_v3_codec_id %d", - codec_id); - self->client_info.v3_codec_id = codec_id; - return 0; + in_uint8(s, codec_id); + g_writeln("xrdp_process_capset_cache_v3_codec_id: cache_v3_codec_id %d", + codec_id); + self->client_info.v3_codec_id = codec_id; + return 0; } /*****************************************************************************/ /* get the number of client cursor cache */ static int APP_CC -xrdp_process_capset_pointercache(struct xrdp_rdp* self, struct stream* s, +xrdp_process_capset_pointercache(struct xrdp_rdp *self, struct stream *s, int len) { - int i; + int i; - in_uint8s(s, 2); /* color pointer */ - in_uint16_le(s, i); - i = MIN(i, 32); - self->client_info.pointer_cache_entries = i; - return 0; + in_uint8s(s, 2); /* color pointer */ + in_uint16_le(s, i); + i = MIN(i, 32); + self->client_info.pointer_cache_entries = i; + return 0; } /*****************************************************************************/ /* get the type of client brush cache */ static int APP_CC -xrdp_process_capset_brushcache(struct xrdp_rdp* self, struct stream* s, +xrdp_process_capset_brushcache(struct xrdp_rdp *self, struct stream *s, int len) { - int code; + int code; - in_uint32_le(s, code); - self->client_info.brush_cache_code = code; - return 0; + in_uint32_le(s, code); + self->client_info.brush_cache_code = code; + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_process_offscreen_bmpcache(struct xrdp_rdp* self, struct stream* s, +xrdp_process_offscreen_bmpcache(struct xrdp_rdp *self, struct stream *s, int len) { - int i32; + int i32; - if (len - 4 < 8) - { - g_writeln("xrdp_process_offscreen_bmpcache: bad len"); - return 1; - } - in_uint32_le(s, i32); - self->client_info.offscreen_support_level = i32; - in_uint16_le(s, i32); - self->client_info.offscreen_cache_size = i32 * 1024; - in_uint16_le(s, i32); - self->client_info.offscreen_cache_entries = i32; - g_writeln("xrdp_process_offscreen_bmpcache: support level %d " - "cache size %d MB cache entries %d", - self->client_info.offscreen_support_level, - self->client_info.offscreen_cache_size, - self->client_info.offscreen_cache_entries); - return 0; + if (len - 4 < 8) + { + g_writeln("xrdp_process_offscreen_bmpcache: bad len"); + return 1; + } + + in_uint32_le(s, i32); + self->client_info.offscreen_support_level = i32; + in_uint16_le(s, i32); + self->client_info.offscreen_cache_size = i32 * 1024; + in_uint16_le(s, i32); + self->client_info.offscreen_cache_entries = i32; + g_writeln("xrdp_process_offscreen_bmpcache: support level %d " + "cache size %d MB cache entries %d", + self->client_info.offscreen_support_level, + self->client_info.offscreen_cache_size, + self->client_info.offscreen_cache_entries); + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_process_capset_rail(struct xrdp_rdp* self, struct stream* s, int len) +xrdp_process_capset_rail(struct xrdp_rdp *self, struct stream *s, int len) { - int i32; + int i32; - if (len - 4 < 4) - { - g_writeln("xrdp_process_capset_rail: bad len"); - return 1; - } - in_uint32_le(s, i32); - self->client_info.rail_support_level = i32; - g_writeln("xrdp_process_capset_rail: rail_support_level %d", - self->client_info.rail_support_level); - return 0; + if (len - 4 < 4) + { + g_writeln("xrdp_process_capset_rail: bad len"); + return 1; + } + + in_uint32_le(s, i32); + self->client_info.rail_support_level = i32; + g_writeln("xrdp_process_capset_rail: rail_support_level %d", + self->client_info.rail_support_level); + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_process_capset_window(struct xrdp_rdp* self, struct stream* s, int len) +xrdp_process_capset_window(struct xrdp_rdp *self, struct stream *s, int len) { - int i32; + int i32; - if (len - 4 < 7) - { - g_writeln("xrdp_process_capset_window: bad len"); - return 1; - } - in_uint32_le(s, i32); - self->client_info.wnd_support_level = i32; - in_uint8(s, i32); - self->client_info.wnd_num_icon_caches = i32; - in_uint16_le(s, i32); - self->client_info.wnd_num_icon_cache_entries = i32; - g_writeln("xrdp_process_capset_window wnd_support_level %d " - "wnd_num_icon_caches %d wnd_num_icon_cache_entries %d", - self->client_info.wnd_support_level, - self->client_info.wnd_num_icon_caches, - self->client_info.wnd_num_icon_cache_entries); - return 0; + if (len - 4 < 7) + { + g_writeln("xrdp_process_capset_window: bad len"); + return 1; + } + + in_uint32_le(s, i32); + self->client_info.wnd_support_level = i32; + in_uint8(s, i32); + self->client_info.wnd_num_icon_caches = i32; + in_uint16_le(s, i32); + self->client_info.wnd_num_icon_cache_entries = i32; + g_writeln("xrdp_process_capset_window wnd_support_level %d " + "wnd_num_icon_caches %d wnd_num_icon_cache_entries %d", + self->client_info.wnd_support_level, + self->client_info.wnd_num_icon_caches, + self->client_info.wnd_num_icon_cache_entries); + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_process_capset_codecs(struct xrdp_rdp* self, struct stream* s, int len) +xrdp_process_capset_codecs(struct xrdp_rdp *self, struct stream *s, int len) { - int codec_id; - int codec_count; - int index; - int codec_properties_length; - int i1; - char* codec_guid; - char* next_guid; + int codec_id; + int codec_count; + int index; + int codec_properties_length; + int i1; + char *codec_guid; + char *next_guid; - in_uint8(s, codec_count); - for (index = 0; index < codec_count; index++) - { - codec_guid = s->p; - in_uint8s(s, 16); - in_uint8(s, codec_id); - in_uint16_le(s, codec_properties_length); - next_guid = s->p + codec_properties_length; - if (g_memcmp(codec_guid, XR_CODEC_GUID_NSCODEC, 16) == 0) + in_uint8(s, codec_count); + + for (index = 0; index < codec_count; index++) { - g_writeln("xrdp_process_capset_codecs: nscodec codec id %d prop len %d", - codec_id, codec_properties_length); - self->client_info.ns_codec_id = codec_id; - i1 = MIN(64, codec_properties_length); - g_memcpy(self->client_info.ns_prop, s->p, i1); - self->client_info.ns_prop_len = i1; + codec_guid = s->p; + in_uint8s(s, 16); + in_uint8(s, codec_id); + in_uint16_le(s, codec_properties_length); + next_guid = s->p + codec_properties_length; + + if (g_memcmp(codec_guid, XR_CODEC_GUID_NSCODEC, 16) == 0) + { + g_writeln("xrdp_process_capset_codecs: nscodec codec id %d prop len %d", + codec_id, codec_properties_length); + self->client_info.ns_codec_id = codec_id; + i1 = MIN(64, codec_properties_length); + g_memcpy(self->client_info.ns_prop, s->p, i1); + self->client_info.ns_prop_len = i1; + } + else if (g_memcmp(codec_guid, XR_CODEC_GUID_REMOTEFX, 16) == 0) + { + g_writeln("xrdp_process_capset_codecs: rfx codec id %d prop len %d", + codec_id, codec_properties_length); + self->client_info.rfx_codec_id = codec_id; + i1 = MIN(64, codec_properties_length); + g_memcpy(self->client_info.rfx_prop, s->p, i1); + self->client_info.rfx_prop_len = i1; + } + else if (g_memcmp(codec_guid, XR_CODEC_GUID_JPEG, 16) == 0) + { + g_writeln("xrdp_process_capset_codecs: jpeg codec id %d prop len %d", + codec_id, codec_properties_length); + self->client_info.jpeg_codec_id = codec_id; + i1 = MIN(64, codec_properties_length); + g_memcpy(self->client_info.jpeg_prop, s->p, i1); + self->client_info.jpeg_prop_len = i1; + g_writeln(" jpeg quality %d", self->client_info.jpeg_prop[0]); + } + else + { + g_writeln("xrdp_process_capset_codecs: unknown codec id %d", codec_id); + } + + s->p = next_guid; } - else if (g_memcmp(codec_guid, XR_CODEC_GUID_REMOTEFX, 16) == 0) - { - g_writeln("xrdp_process_capset_codecs: rfx codec id %d prop len %d", - codec_id, codec_properties_length); - self->client_info.rfx_codec_id = codec_id; - i1 = MIN(64, codec_properties_length); - g_memcpy(self->client_info.rfx_prop, s->p, i1); - self->client_info.rfx_prop_len = i1; - } - else if (g_memcmp(codec_guid, XR_CODEC_GUID_JPEG, 16) == 0) - { - g_writeln("xrdp_process_capset_codecs: jpeg codec id %d prop len %d", - codec_id, codec_properties_length); - self->client_info.jpeg_codec_id = codec_id; - i1 = MIN(64, codec_properties_length); - g_memcpy(self->client_info.jpeg_prop, s->p, i1); - self->client_info.jpeg_prop_len = i1; - g_writeln(" jpeg quality %d", self->client_info.jpeg_prop[0]); - } - else - { - g_writeln("xrdp_process_capset_codecs: unknown codec id %d", codec_id); - } - s->p = next_guid; - } - return 0; + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_rdp_process_confirm_active(struct xrdp_rdp* self, struct stream* s) +xrdp_rdp_process_confirm_active(struct xrdp_rdp *self, struct stream *s) { - int cap_len; - int source_len; - int num_caps; - int index; - int type; - int len; - char* p; + int cap_len; + int source_len; + int num_caps; + int index; + int type; + int len; + char *p; - DEBUG(("in xrdp_rdp_process_confirm_active")); - in_uint8s(s, 4); /* rdp_shareid */ - in_uint8s(s, 2); /* userid */ - in_uint16_le(s, source_len); /* sizeof RDP_SOURCE */ - in_uint16_le(s, cap_len); - in_uint8s(s, source_len); - in_uint16_le(s, num_caps); - in_uint8s(s, 2); /* pad */ - for (index = 0; index < num_caps; index++) - { - p = s->p; - in_uint16_le(s, type); - in_uint16_le(s, len); - switch (type) + DEBUG(("in xrdp_rdp_process_confirm_active")); + in_uint8s(s, 4); /* rdp_shareid */ + in_uint8s(s, 2); /* userid */ + in_uint16_le(s, source_len); /* sizeof RDP_SOURCE */ + in_uint16_le(s, cap_len); + in_uint8s(s, source_len); + in_uint16_le(s, num_caps); + in_uint8s(s, 2); /* pad */ + + for (index = 0; index < num_caps; index++) { - case RDP_CAPSET_GENERAL: /* 1 */ - DEBUG(("RDP_CAPSET_GENERAL")); - xrdp_process_capset_general(self, s, len); - break; - case RDP_CAPSET_BITMAP: /* 2 */ - DEBUG(("RDP_CAPSET_BITMAP")); - break; - case RDP_CAPSET_ORDER: /* 3 */ - DEBUG(("RDP_CAPSET_ORDER")); - xrdp_process_capset_order(self, s, len); - break; - case RDP_CAPSET_BMPCACHE: /* 4 */ - DEBUG(("RDP_CAPSET_BMPCACHE")); - xrdp_process_capset_bmpcache(self, s, len); - break; - case RDP_CAPSET_CONTROL: /* 5 */ - DEBUG(("RDP_CAPSET_CONTROL")); - break; - case 6: - xrdp_process_capset_cache_v3_codec_id(self, s, len); - break; - case RDP_CAPSET_ACTIVATE: /* 7 */ - DEBUG(("RDP_CAPSET_ACTIVATE")); - break; - case RDP_CAPSET_POINTER: /* 8 */ - DEBUG(("RDP_CAPSET_POINTER")); - xrdp_process_capset_pointercache(self, s, len); - break; - case RDP_CAPSET_SHARE: /* 9 */ - DEBUG(("RDP_CAPSET_SHARE")); - break; - case RDP_CAPSET_COLCACHE: /* 10 */ - DEBUG(("RDP_CAPSET_COLCACHE")); - break; - case 12: /* 12 */ - DEBUG(("--12")); - break; - case 13: /* 13 */ - DEBUG(("--13")); - break; - case 14: /* 14 */ - DEBUG(("--14")); - break; - case RDP_CAPSET_BRUSHCACHE: /* 15 */ - xrdp_process_capset_brushcache(self, s, len); - break; - case 16: /* 16 */ - DEBUG(("--16")); - break; - case 17: /* 17 */ - DEBUG(("CAPSET_TYPE_OFFSCREEN_CACHE")); - xrdp_process_offscreen_bmpcache(self, s, len); - break; - case RDP_CAPSET_BMPCACHE2: /* 19 */ - DEBUG(("RDP_CAPSET_BMPCACHE2")); - xrdp_process_capset_bmpcache2(self, s, len); - break; - case 20: /* 20 */ - DEBUG(("--20")); - break; - case 21: /* 21 */ - DEBUG(("--21")); - break; - case 22: /* 22 */ - DEBUG(("--22")); - break; - case 0x0017: /* 23 CAPSETTYPE_RAIL */ - xrdp_process_capset_rail(self, s, len); - break; - case 0x0018: /* 24 CAPSETTYPE_WINDOW */ - xrdp_process_capset_window(self, s, len); - break; - case 26: /* 26 */ - DEBUG(("--26")); - break; - case RDP_CAPSET_BMPCODECS: /* 0x1d(29) */ - xrdp_process_capset_codecs(self, s, len); - break; - default: - g_writeln("unknown in xrdp_rdp_process_confirm_active %d", type); - break; + p = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + + switch (type) + { + case RDP_CAPSET_GENERAL: /* 1 */ + DEBUG(("RDP_CAPSET_GENERAL")); + xrdp_process_capset_general(self, s, len); + break; + case RDP_CAPSET_BITMAP: /* 2 */ + DEBUG(("RDP_CAPSET_BITMAP")); + break; + case RDP_CAPSET_ORDER: /* 3 */ + DEBUG(("RDP_CAPSET_ORDER")); + xrdp_process_capset_order(self, s, len); + break; + case RDP_CAPSET_BMPCACHE: /* 4 */ + DEBUG(("RDP_CAPSET_BMPCACHE")); + xrdp_process_capset_bmpcache(self, s, len); + break; + case RDP_CAPSET_CONTROL: /* 5 */ + DEBUG(("RDP_CAPSET_CONTROL")); + break; + case 6: + xrdp_process_capset_cache_v3_codec_id(self, s, len); + break; + case RDP_CAPSET_ACTIVATE: /* 7 */ + DEBUG(("RDP_CAPSET_ACTIVATE")); + break; + case RDP_CAPSET_POINTER: /* 8 */ + DEBUG(("RDP_CAPSET_POINTER")); + xrdp_process_capset_pointercache(self, s, len); + break; + case RDP_CAPSET_SHARE: /* 9 */ + DEBUG(("RDP_CAPSET_SHARE")); + break; + case RDP_CAPSET_COLCACHE: /* 10 */ + DEBUG(("RDP_CAPSET_COLCACHE")); + break; + case 12: /* 12 */ + DEBUG(("--12")); + break; + case 13: /* 13 */ + DEBUG(("--13")); + break; + case 14: /* 14 */ + DEBUG(("--14")); + break; + case RDP_CAPSET_BRUSHCACHE: /* 15 */ + xrdp_process_capset_brushcache(self, s, len); + break; + case 16: /* 16 */ + DEBUG(("--16")); + break; + case 17: /* 17 */ + DEBUG(("CAPSET_TYPE_OFFSCREEN_CACHE")); + xrdp_process_offscreen_bmpcache(self, s, len); + break; + case RDP_CAPSET_BMPCACHE2: /* 19 */ + DEBUG(("RDP_CAPSET_BMPCACHE2")); + xrdp_process_capset_bmpcache2(self, s, len); + break; + case 20: /* 20 */ + DEBUG(("--20")); + break; + case 21: /* 21 */ + DEBUG(("--21")); + break; + case 22: /* 22 */ + DEBUG(("--22")); + break; + case 0x0017: /* 23 CAPSETTYPE_RAIL */ + xrdp_process_capset_rail(self, s, len); + break; + case 0x0018: /* 24 CAPSETTYPE_WINDOW */ + xrdp_process_capset_window(self, s, len); + break; + case 26: /* 26 */ + DEBUG(("--26")); + break; + case RDP_CAPSET_BMPCODECS: /* 0x1d(29) */ + xrdp_process_capset_codecs(self, s, len); + break; + default: + g_writeln("unknown in xrdp_rdp_process_confirm_active %d", type); + break; + } + + s->p = p + len; } - s->p = p + len; - } - DEBUG(("out xrdp_rdp_process_confirm_active")); - return 0; + + DEBUG(("out xrdp_rdp_process_confirm_active")); + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_rdp_process_data_pointer(struct xrdp_rdp* self, struct stream* s) +xrdp_rdp_process_data_pointer(struct xrdp_rdp *self, struct stream *s) { - return 0; + return 0; } /*****************************************************************************/ /* RDP_DATA_PDU_INPUT */ static int APP_CC -xrdp_rdp_process_data_input(struct xrdp_rdp* self, struct stream* s) +xrdp_rdp_process_data_input(struct xrdp_rdp *self, struct stream *s) { - int num_events; - int index; - int msg_type; - int device_flags; - int param1; - int param2; - int time; + int num_events; + int index; + int msg_type; + int device_flags; + int param1; + int param2; + int time; - in_uint16_le(s, num_events); - in_uint8s(s, 2); /* pad */ - DEBUG(("in xrdp_rdp_process_data_input %d events", num_events)); - for (index = 0; index < num_events; index++) - { - in_uint32_le(s, time); - in_uint16_le(s, msg_type); - in_uint16_le(s, device_flags); - in_sint16_le(s, param1); - in_sint16_le(s, param2); - DEBUG(("xrdp_rdp_process_data_input event %4.4x flags %4.4x param1 %d \ + in_uint16_le(s, num_events); + in_uint8s(s, 2); /* pad */ + DEBUG(("in xrdp_rdp_process_data_input %d events", num_events)); + + for (index = 0; index < num_events; index++) + { + in_uint32_le(s, time); + in_uint16_le(s, msg_type); + in_uint16_le(s, device_flags); + in_sint16_le(s, param1); + in_sint16_le(s, param2); + DEBUG(("xrdp_rdp_process_data_input event %4.4x flags %4.4x param1 %d \ param2 %d time %d", msg_type, device_flags, param1, param2, time)); + + if (self->session->callback != 0) + { + /* msg_type can be + RDP_INPUT_SYNCHRONIZE - 0 + RDP_INPUT_SCANCODE - 4 + RDP_INPUT_MOUSE - 0x8001 */ + /* call to xrdp_wm.c : callback */ + self->session->callback(self->session->id, msg_type, param1, param2, + device_flags, time); + } + } + + DEBUG(("out xrdp_rdp_process_data_input")); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_send_synchronise(struct xrdp_rdp *self) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint16_le(s, 1); + out_uint16_le(s, 1002); + s_mark_end(s); + + if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_SYNCHRONISE) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_send_control(struct xrdp_rdp *self, int action) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint16_le(s, action); + out_uint16_le(s, 0); /* userid */ + out_uint32_le(s, 1002); /* control id */ + s_mark_end(s); + + if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_CONTROL) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_process_data_control(struct xrdp_rdp *self, struct stream *s) +{ + int action; + + DEBUG(("xrdp_rdp_process_data_control")); + in_uint16_le(s, action); + in_uint8s(s, 2); /* user id */ + in_uint8s(s, 4); /* control id */ + + if (action == RDP_CTL_REQUEST_CONTROL) + { + DEBUG(("xrdp_rdp_process_data_control got RDP_CTL_REQUEST_CONTROL")); + DEBUG(("xrdp_rdp_process_data_control calling xrdp_rdp_send_synchronise")); + xrdp_rdp_send_synchronise(self); + DEBUG(("xrdp_rdp_process_data_control sending RDP_CTL_COOPERATE")); + xrdp_rdp_send_control(self, RDP_CTL_COOPERATE); + DEBUG(("xrdp_rdp_process_data_control sending RDP_CTL_GRANT_CONTROL")); + xrdp_rdp_send_control(self, RDP_CTL_GRANT_CONTROL); + } + else + { + DEBUG(("xrdp_rdp_process_data_control unknown action")); + } + + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_process_data_sync(struct xrdp_rdp *self) +{ + DEBUG(("xrdp_rdp_process_data_sync")); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_rdp_process_screen_update(struct xrdp_rdp *self, struct stream *s) +{ + int op; + int left; + int top; + int right; + int bottom; + int cx; + int cy; + + in_uint32_le(s, op); + in_uint16_le(s, left); + in_uint16_le(s, top); + in_uint16_le(s, right); + in_uint16_le(s, bottom); + cx = (right - left) + 1; + cy = (bottom - top) + 1; + if (self->session->callback != 0) { - /* msg_type can be - RDP_INPUT_SYNCHRONIZE - 0 - RDP_INPUT_SCANCODE - 4 - RDP_INPUT_MOUSE - 0x8001 */ - /* call to xrdp_wm.c : callback */ - self->session->callback(self->session->id, msg_type, param1, param2, - device_flags, time); + self->session->callback(self->session->id, 0x4444, left, top, cx, cy); } - } - DEBUG(("out xrdp_rdp_process_data_input")); - return 0; + + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_rdp_send_synchronise(struct xrdp_rdp* self) +xrdp_rdp_send_unknown1(struct xrdp_rdp *self) { - struct stream* s; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint8a(s, g_unknown1, 172); + s_mark_end(s); + + if (xrdp_rdp_send_data(self, s, 0x28) != 0) + { + free_stream(s); + return 1; + } - make_stream(s); - init_stream(s, 8192); - if (xrdp_rdp_init_data(self, s) != 0) - { free_stream(s); - return 1; - } - out_uint16_le(s, 1); - out_uint16_le(s, 1002); - s_mark_end(s); - if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_SYNCHRONISE) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_rdp_send_control(struct xrdp_rdp* self, int action) +xrdp_rdp_process_data_font(struct xrdp_rdp *self, struct stream *s) { - struct stream* s; + int seq; - make_stream(s); - init_stream(s, 8192); - if (xrdp_rdp_init_data(self, s) != 0) - { - free_stream(s); - return 1; - } - out_uint16_le(s, action); - out_uint16_le(s, 0); /* userid */ - out_uint32_le(s, 1002); /* control id */ - s_mark_end(s); - if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_CONTROL) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} + DEBUG(("in xrdp_rdp_process_data_font")); + in_uint8s(s, 2); /* num of fonts */ + in_uint8s(s, 2); /* unknown */ + in_uint16_le(s, seq); -/*****************************************************************************/ -static int APP_CC -xrdp_rdp_process_data_control(struct xrdp_rdp* self, struct stream* s) -{ - int action; + /* 419 client sends Seq 1, then 2 */ + /* 2600 clients sends only Seq 3 */ + if (seq == 2 || seq == 3) /* after second font message, we are up and */ + { + /* running */ + DEBUG(("sending unknown1")); + xrdp_rdp_send_unknown1(self); + self->session->up_and_running = 1; + DEBUG(("up_and_running set")); + xrdp_rdp_send_data_update_sync(self); + } - DEBUG(("xrdp_rdp_process_data_control")); - in_uint16_le(s, action); - in_uint8s(s, 2); /* user id */ - in_uint8s(s, 4); /* control id */ - if (action == RDP_CTL_REQUEST_CONTROL) - { - DEBUG(("xrdp_rdp_process_data_control got RDP_CTL_REQUEST_CONTROL")); - DEBUG(("xrdp_rdp_process_data_control calling xrdp_rdp_send_synchronise")); - xrdp_rdp_send_synchronise(self); - DEBUG(("xrdp_rdp_process_data_control sending RDP_CTL_COOPERATE")); - xrdp_rdp_send_control(self, RDP_CTL_COOPERATE); - DEBUG(("xrdp_rdp_process_data_control sending RDP_CTL_GRANT_CONTROL")); - xrdp_rdp_send_control(self, RDP_CTL_GRANT_CONTROL); - } - else - { - DEBUG(("xrdp_rdp_process_data_control unknown action")); - } - return 0; -} - -/*****************************************************************************/ -static int APP_CC -xrdp_rdp_process_data_sync(struct xrdp_rdp* self) -{ - DEBUG(("xrdp_rdp_process_data_sync")); - return 0; -} - -/*****************************************************************************/ -static int APP_CC -xrdp_rdp_process_screen_update(struct xrdp_rdp* self, struct stream* s) -{ - int op; - int left; - int top; - int right; - int bottom; - int cx; - int cy; - - in_uint32_le(s, op); - in_uint16_le(s, left); - in_uint16_le(s, top); - in_uint16_le(s, right); - in_uint16_le(s, bottom); - cx = (right - left) + 1; - cy = (bottom - top) + 1; - if (self->session->callback != 0) - { - self->session->callback(self->session->id, 0x4444, left, top, cx, cy); - } - return 0; -} - -/*****************************************************************************/ -static int APP_CC -xrdp_rdp_send_unknown1(struct xrdp_rdp* self) -{ - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (xrdp_rdp_init_data(self, s) != 0) - { - free_stream(s); - return 1; - } - out_uint8a(s, g_unknown1, 172); - s_mark_end(s); - if (xrdp_rdp_send_data(self, s, 0x28) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -static int APP_CC -xrdp_rdp_process_data_font(struct xrdp_rdp* self, struct stream* s) -{ - int seq; - - DEBUG(("in xrdp_rdp_process_data_font")); - in_uint8s(s, 2); /* num of fonts */ - in_uint8s(s, 2); /* unknown */ - in_uint16_le(s, seq); - /* 419 client sends Seq 1, then 2 */ - /* 2600 clients sends only Seq 3 */ - if (seq == 2 || seq == 3) /* after second font message, we are up and */ - { /* running */ - DEBUG(("sending unknown1")); - xrdp_rdp_send_unknown1(self); - self->session->up_and_running = 1; - DEBUG(("up_and_running set")); - xrdp_rdp_send_data_update_sync(self); - } - DEBUG(("out xrdp_rdp_process_data_font")); - return 0; + DEBUG(("out xrdp_rdp_process_data_font")); + return 0; } /*****************************************************************************/ /* sent 37 pdu */ static int APP_CC -xrdp_rdp_send_disconnect_query_response(struct xrdp_rdp* self) +xrdp_rdp_send_disconnect_query_response(struct xrdp_rdp *self) { - struct stream* s; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + + s_mark_end(s); + + if (xrdp_rdp_send_data(self, s, 37) != 0) + { + free_stream(s); + return 1; + } - make_stream(s); - init_stream(s, 8192); - if (xrdp_rdp_init_data(self, s) != 0) - { free_stream(s); - return 1; - } - s_mark_end(s); - if (xrdp_rdp_send_data(self, s, 37) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; + return 0; } #if 0 /* not used */ /*****************************************************************************/ /* sent RDP_DATA_PDU_DISCONNECT 47 pdu */ static int APP_CC -xrdp_rdp_send_disconnect_reason(struct xrdp_rdp* self, int reason) +xrdp_rdp_send_disconnect_reason(struct xrdp_rdp *self, int reason) { - struct stream* s; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_rdp_init_data(self, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint32_le(s, reason); + s_mark_end(s); + + if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_DISCONNECT) != 0) + { + free_stream(s); + return 1; + } - make_stream(s); - init_stream(s, 8192); - if (xrdp_rdp_init_data(self, s) != 0) - { free_stream(s); - return 1; - } - out_uint32_le(s, reason); - s_mark_end(s); - if (xrdp_rdp_send_data(self, s, RDP_DATA_PDU_DISCONNECT) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; + return 0; } #endif /*****************************************************************************/ /* RDP_PDU_DATA */ int APP_CC -xrdp_rdp_process_data(struct xrdp_rdp* self, struct stream* s) +xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s) { - int len; - int data_type; - int ctype; - int clen; + int len; + int data_type; + int ctype; + int clen; - in_uint8s(s, 6); - in_uint16_le(s, len); - in_uint8(s, data_type); - in_uint8(s, ctype); - in_uint16_le(s, clen); - DEBUG(("xrdp_rdp_process_data code %d", data_type)); - switch (data_type) - { - case RDP_DATA_PDU_POINTER: /* 27(0x1b) */ - xrdp_rdp_process_data_pointer(self, s); - break; - case RDP_DATA_PDU_INPUT: /* 28(0x1c) */ - xrdp_rdp_process_data_input(self, s); - break; - case RDP_DATA_PDU_CONTROL: /* 20(0x14) */ - xrdp_rdp_process_data_control(self, s); - break; - case RDP_DATA_PDU_SYNCHRONISE: /* 31(0x1f) */ - xrdp_rdp_process_data_sync(self); - break; - case 33: /* 33(0x21) ?? Invalidate an area I think */ - xrdp_rdp_process_screen_update(self, s); - break; - case 35: /* 35(0x23) */ - /* 35 ?? this comes when minimuzing a full screen mstsc.exe 2600 */ - /* I think this is saying the client no longer wants screen */ - /* updates and it will issue a 33 above to catch up */ - /* so minimized apps don't take bandwidth */ - break; - case 36: /* 36(0x24) ?? disconnect query? */ - /* when this message comes, send a 37 back so the client */ - /* is sure the connection is alive and it can ask if user */ - /* really wants to disconnect */ - xrdp_rdp_send_disconnect_query_response(self); /* send a 37 back */ - break; - case RDP_DATA_PDU_FONT2: /* 39(0x27) */ - xrdp_rdp_process_data_font(self, s); - break; - default: - g_writeln("unknown in xrdp_rdp_process_data %d", data_type); - break; - } - return 0; + in_uint8s(s, 6); + in_uint16_le(s, len); + in_uint8(s, data_type); + in_uint8(s, ctype); + in_uint16_le(s, clen); + DEBUG(("xrdp_rdp_process_data code %d", data_type)); + + switch (data_type) + { + case RDP_DATA_PDU_POINTER: /* 27(0x1b) */ + xrdp_rdp_process_data_pointer(self, s); + break; + case RDP_DATA_PDU_INPUT: /* 28(0x1c) */ + xrdp_rdp_process_data_input(self, s); + break; + case RDP_DATA_PDU_CONTROL: /* 20(0x14) */ + xrdp_rdp_process_data_control(self, s); + break; + case RDP_DATA_PDU_SYNCHRONISE: /* 31(0x1f) */ + xrdp_rdp_process_data_sync(self); + break; + case 33: /* 33(0x21) ?? Invalidate an area I think */ + xrdp_rdp_process_screen_update(self, s); + break; + case 35: /* 35(0x23) */ + /* 35 ?? this comes when minimuzing a full screen mstsc.exe 2600 */ + /* I think this is saying the client no longer wants screen */ + /* updates and it will issue a 33 above to catch up */ + /* so minimized apps don't take bandwidth */ + break; + case 36: /* 36(0x24) ?? disconnect query? */ + /* when this message comes, send a 37 back so the client */ + /* is sure the connection is alive and it can ask if user */ + /* really wants to disconnect */ + xrdp_rdp_send_disconnect_query_response(self); /* send a 37 back */ + break; + case RDP_DATA_PDU_FONT2: /* 39(0x27) */ + xrdp_rdp_process_data_font(self, s); + break; + default: + g_writeln("unknown in xrdp_rdp_process_data %d", data_type); + break; + } + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_rdp_disconnect(struct xrdp_rdp* self) +xrdp_rdp_disconnect(struct xrdp_rdp *self) { - int rv; + int rv; - DEBUG(("in xrdp_rdp_disconnect")); - rv = xrdp_sec_disconnect(self->sec_layer); - DEBUG(("out xrdp_rdp_disconnect")); - return rv; + DEBUG(("in xrdp_rdp_disconnect")); + rv = xrdp_sec_disconnect(self->sec_layer); + DEBUG(("out xrdp_rdp_disconnect")); + return rv; } /*****************************************************************************/ int APP_CC -xrdp_rdp_send_deactive(struct xrdp_rdp* self) +xrdp_rdp_send_deactive(struct xrdp_rdp *self) { - struct stream* s; + struct stream *s; + + DEBUG(("in xrdp_rdp_send_deactive")); + make_stream(s); + init_stream(s, 8192); + + if (xrdp_rdp_init(self, s) != 0) + { + free_stream(s); + DEBUG(("out xrdp_rdp_send_deactive error")); + return 1; + } + + s_mark_end(s); + + if (xrdp_rdp_send(self, s, RDP_PDU_DEACTIVATE) != 0) + { + free_stream(s); + DEBUG(("out xrdp_rdp_send_deactive error")); + return 1; + } - DEBUG(("in xrdp_rdp_send_deactive")); - make_stream(s); - init_stream(s, 8192); - if (xrdp_rdp_init(self, s) != 0) - { free_stream(s); - DEBUG(("out xrdp_rdp_send_deactive error")); - return 1; - } - s_mark_end(s); - if (xrdp_rdp_send(self, s, RDP_PDU_DEACTIVATE) != 0) - { - free_stream(s); - DEBUG(("out xrdp_rdp_send_deactive error")); - return 1; - } - free_stream(s); - DEBUG(("out xrdp_rdp_send_deactive")); - return 0; + DEBUG(("out xrdp_rdp_send_deactive")); + return 0; } diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 381e8435..66b66264 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -1,1008 +1,1111 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - secure layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * secure layer + */ #include "libxrdp.h" /* some compilers need unsigned char to avoid warnings */ static tui8 g_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 }; +{ + 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 +}; /* some compilers need unsigned char to avoid warnings */ static tui8 g_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 }; +{ + 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 +}; /* some compilers need unsigned char to avoid warnings */ static tui8 g_lic1[322] = -{ 0x80, 0x00, 0x3e, 0x01, 0x01, 0x02, 0x3e, 0x01, - 0x7b, 0x3c, 0x31, 0xa6, 0xae, 0xe8, 0x74, 0xf6, - 0xb4, 0xa5, 0x03, 0x90, 0xe7, 0xc2, 0xc7, 0x39, - 0xba, 0x53, 0x1c, 0x30, 0x54, 0x6e, 0x90, 0x05, - 0xd0, 0x05, 0xce, 0x44, 0x18, 0x91, 0x83, 0x81, - 0x00, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, - 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, - 0x74, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, - 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, - 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x33, 0x00, 0x36, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x03, 0x00, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x5c, 0x00, 0x52, 0x53, 0x41, 0x31, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x01, 0xc7, 0xc9, 0xf7, 0x8e, 0x5a, 0x38, 0xe4, - 0x29, 0xc3, 0x00, 0x95, 0x2d, 0xdd, 0x4c, 0x3e, - 0x50, 0x45, 0x0b, 0x0d, 0x9e, 0x2a, 0x5d, 0x18, - 0x63, 0x64, 0xc4, 0x2c, 0xf7, 0x8f, 0x29, 0xd5, - 0x3f, 0xc5, 0x35, 0x22, 0x34, 0xff, 0xad, 0x3a, - 0xe6, 0xe3, 0x95, 0x06, 0xae, 0x55, 0x82, 0xe3, - 0xc8, 0xc7, 0xb4, 0xa8, 0x47, 0xc8, 0x50, 0x71, - 0x74, 0x29, 0x53, 0x89, 0x6d, 0x9c, 0xed, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x48, 0x00, 0xa8, 0xf4, 0x31, 0xb9, - 0xab, 0x4b, 0xe6, 0xb4, 0xf4, 0x39, 0x89, 0xd6, - 0xb1, 0xda, 0xf6, 0x1e, 0xec, 0xb1, 0xf0, 0x54, - 0x3b, 0x5e, 0x3e, 0x6a, 0x71, 0xb4, 0xf7, 0x75, - 0xc8, 0x16, 0x2f, 0x24, 0x00, 0xde, 0xe9, 0x82, - 0x99, 0x5f, 0x33, 0x0b, 0xa9, 0xa6, 0x94, 0xaf, - 0xcb, 0x11, 0xc3, 0xf2, 0xdb, 0x09, 0x42, 0x68, - 0x29, 0x56, 0x58, 0x01, 0x56, 0xdb, 0x59, 0x03, - 0x69, 0xdb, 0x7d, 0x37, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x0e, 0x00, 0x6d, 0x69, 0x63, 0x72, - 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, - 0x6d, 0x00 }; +{ + 0x80, 0x00, 0x3e, 0x01, 0x01, 0x02, 0x3e, 0x01, + 0x7b, 0x3c, 0x31, 0xa6, 0xae, 0xe8, 0x74, 0xf6, + 0xb4, 0xa5, 0x03, 0x90, 0xe7, 0xc2, 0xc7, 0x39, + 0xba, 0x53, 0x1c, 0x30, 0x54, 0x6e, 0x90, 0x05, + 0xd0, 0x05, 0xce, 0x44, 0x18, 0x91, 0x83, 0x81, + 0x00, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, + 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, + 0x74, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, + 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, + 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, + 0x6e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x33, 0x00, 0x36, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x5c, 0x00, 0x52, 0x53, 0x41, 0x31, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x3f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0xc7, 0xc9, 0xf7, 0x8e, 0x5a, 0x38, 0xe4, + 0x29, 0xc3, 0x00, 0x95, 0x2d, 0xdd, 0x4c, 0x3e, + 0x50, 0x45, 0x0b, 0x0d, 0x9e, 0x2a, 0x5d, 0x18, + 0x63, 0x64, 0xc4, 0x2c, 0xf7, 0x8f, 0x29, 0xd5, + 0x3f, 0xc5, 0x35, 0x22, 0x34, 0xff, 0xad, 0x3a, + 0xe6, 0xe3, 0x95, 0x06, 0xae, 0x55, 0x82, 0xe3, + 0xc8, 0xc7, 0xb4, 0xa8, 0x47, 0xc8, 0x50, 0x71, + 0x74, 0x29, 0x53, 0x89, 0x6d, 0x9c, 0xed, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x48, 0x00, 0xa8, 0xf4, 0x31, 0xb9, + 0xab, 0x4b, 0xe6, 0xb4, 0xf4, 0x39, 0x89, 0xd6, + 0xb1, 0xda, 0xf6, 0x1e, 0xec, 0xb1, 0xf0, 0x54, + 0x3b, 0x5e, 0x3e, 0x6a, 0x71, 0xb4, 0xf7, 0x75, + 0xc8, 0x16, 0x2f, 0x24, 0x00, 0xde, 0xe9, 0x82, + 0x99, 0x5f, 0x33, 0x0b, 0xa9, 0xa6, 0x94, 0xaf, + 0xcb, 0x11, 0xc3, 0xf2, 0xdb, 0x09, 0x42, 0x68, + 0x29, 0x56, 0x58, 0x01, 0x56, 0xdb, 0x59, 0x03, + 0x69, 0xdb, 0x7d, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x6d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x00 +}; /* some compilers need unsigned char to avoid warnings */ static tui8 g_lic2[20] = -{ 0x80, 0x00, 0x10, 0x00, 0xff, 0x02, 0x10, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x28, 0x14, 0x00, 0x00 }; +{ + 0x80, 0x00, 0x10, 0x00, 0xff, 0x02, 0x10, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x28, 0x14, 0x00, 0x00 +}; /* mce */ /* some compilers need unsigned char to avoid warnings */ static tui8 g_lic3[20] = -{ 0x80, 0x02, 0x10, 0x00, 0xff, 0x03, 0x10, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xf3, 0x99, 0x00, 0x00 }; +{ + 0x80, 0x02, 0x10, 0x00, 0xff, 0x03, 0x10, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xf3, 0x99, 0x00, 0x00 +}; /*****************************************************************************/ static void APP_CC -hex_str_to_bin(char* in, char* out, int out_len) +hex_str_to_bin(char *in, char *out, int out_len) { - int in_index; - int in_len; - int out_index; - int val; - char hex[16]; + int in_index; + int in_len; + int out_index; + int val; + char hex[16]; - in_len = g_strlen(in); - out_index = 0; - in_index = 0; - while (in_index <= (in_len - 4)) - { - if ((in[in_index] == '0') && (in[in_index + 1] == 'x')) + in_len = g_strlen(in); + out_index = 0; + in_index = 0; + + while (in_index <= (in_len - 4)) { - hex[0] = in[in_index + 2]; - hex[1] = in[in_index + 3]; - hex[2] = 0; - if (out_index < out_len) - { - val = g_htoi(hex); - out[out_index] = val; - } - out_index++; + if ((in[in_index] == '0') && (in[in_index + 1] == 'x')) + { + hex[0] = in[in_index + 2]; + hex[1] = in[in_index + 3]; + hex[2] = 0; + + if (out_index < out_len) + { + val = g_htoi(hex); + out[out_index] = val; + } + + out_index++; + } + + in_index++; } - in_index++; - } } /*****************************************************************************/ -struct xrdp_sec* APP_CC -xrdp_sec_create(struct xrdp_rdp* owner, struct trans* trans, int crypt_level, +struct xrdp_sec *APP_CC +xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans, int crypt_level, int channel_code) { - struct xrdp_sec* self; + struct xrdp_sec *self; - DEBUG((" in xrdp_sec_create")); - self = (struct xrdp_sec*)g_malloc(sizeof(struct xrdp_sec), 1); - self->rdp_layer = owner; - self->rc4_key_size = 1; /* 1 = 40 bit, 2 = 128 bit */ - self->crypt_level = 1; /* 1, 2, 3 = low, medium, high */ - switch (crypt_level) - { - case 1: - self->rc4_key_size = 1; - self->crypt_level = 1; - break; - case 2: - self->rc4_key_size = 1; - self->crypt_level = 2; - break; - case 3: - self->rc4_key_size = 2; - self->crypt_level = 3; - break; - default: - g_writeln("Fatal : Illegal crypt_level"); - break ; - } - self->channel_code = channel_code; - if(self->decrypt_rc4_info!=NULL) - { - g_writeln("xrdp_sec_create - decrypt_rc4_info already created !!!"); - } - self->decrypt_rc4_info = ssl_rc4_info_create(); - if(self->encrypt_rc4_info!=NULL) - { - g_writeln("xrdp_sec_create - encrypt_rc4_info already created !!!"); - } - self->encrypt_rc4_info = ssl_rc4_info_create(); - self->mcs_layer = xrdp_mcs_create(self, trans, &self->client_mcs_data, - &self->server_mcs_data); - self->chan_layer = xrdp_channel_create(self, self->mcs_layer); - DEBUG((" out xrdp_sec_create")); - return self; + DEBUG((" in xrdp_sec_create")); + self = (struct xrdp_sec *)g_malloc(sizeof(struct xrdp_sec), 1); + self->rdp_layer = owner; + self->rc4_key_size = 1; /* 1 = 40 bit, 2 = 128 bit */ + self->crypt_level = 1; /* 1, 2, 3 = low, medium, high */ + + switch (crypt_level) + { + case 1: + self->rc4_key_size = 1; + self->crypt_level = 1; + break; + case 2: + self->rc4_key_size = 1; + self->crypt_level = 2; + break; + case 3: + self->rc4_key_size = 2; + self->crypt_level = 3; + break; + default: + g_writeln("Fatal : Illegal crypt_level"); + break ; + } + + self->channel_code = channel_code; + + if (self->decrypt_rc4_info != NULL) + { + g_writeln("xrdp_sec_create - decrypt_rc4_info already created !!!"); + } + + self->decrypt_rc4_info = ssl_rc4_info_create(); + + if (self->encrypt_rc4_info != NULL) + { + g_writeln("xrdp_sec_create - encrypt_rc4_info already created !!!"); + } + + self->encrypt_rc4_info = ssl_rc4_info_create(); + self->mcs_layer = xrdp_mcs_create(self, trans, &self->client_mcs_data, + &self->server_mcs_data); + self->chan_layer = xrdp_channel_create(self, self->mcs_layer); + DEBUG((" out xrdp_sec_create")); + return self; } /*****************************************************************************/ void APP_CC -xrdp_sec_delete(struct xrdp_sec* self) +xrdp_sec_delete(struct xrdp_sec *self) { - if (self == 0) - { - g_writeln("xrdp_sec_delete: indata is null"); - return; - } - xrdp_channel_delete(self->chan_layer); - xrdp_mcs_delete(self->mcs_layer); - ssl_rc4_info_delete(self->decrypt_rc4_info); /* TODO clear all data */ - ssl_rc4_info_delete(self->encrypt_rc4_info); /* TODO clear all data */ - g_free(self->client_mcs_data.data); - g_free(self->server_mcs_data.data); - /* Crypto information must always be cleared */ - g_memset(self,0,sizeof(struct xrdp_sec)); - g_free(self); + if (self == 0) + { + g_writeln("xrdp_sec_delete: indata is null"); + return; + } + + xrdp_channel_delete(self->chan_layer); + xrdp_mcs_delete(self->mcs_layer); + ssl_rc4_info_delete(self->decrypt_rc4_info); /* TODO clear all data */ + ssl_rc4_info_delete(self->encrypt_rc4_info); /* TODO clear all data */ + g_free(self->client_mcs_data.data); + g_free(self->server_mcs_data.data); + /* Crypto information must always be cleared */ + g_memset(self, 0, sizeof(struct xrdp_sec)); + g_free(self); } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_sec_init(struct xrdp_sec* self, struct stream* s) +xrdp_sec_init(struct xrdp_sec *self, struct stream *s) { - if (xrdp_mcs_init(self->mcs_layer, s) != 0) - { - return 1; - } - if (self->crypt_level > 1) - { - s_push_layer(s, sec_hdr, 4 + 8); - } - else - { - s_push_layer(s, sec_hdr, 4); - } - return 0; + if (xrdp_mcs_init(self->mcs_layer, s) != 0) + { + return 1; + } + + if (self->crypt_level > 1) + { + s_push_layer(s, sec_hdr, 4 + 8); + } + else + { + s_push_layer(s, sec_hdr, 4); + } + + return 0; } /*****************************************************************************/ /* Reduce key entropy from 64 to 40 bits */ static void APP_CC -xrdp_sec_make_40bit(char* key) +xrdp_sec_make_40bit(char *key) { - key[0] = 0xd1; - key[1] = 0x26; - key[2] = 0x9e; + key[0] = 0xd1; + key[1] = 0x26; + key[2] = 0x9e; } /*****************************************************************************/ /* returns error */ /* update an encryption key */ static int APP_CC -xrdp_sec_update(char* key, char* update_key, int key_len) +xrdp_sec_update(char *key, char *update_key, int key_len) { - char shasig[20]; - void* sha1_info; - void* md5_info; - void* rc4_info; + char shasig[20]; + void *sha1_info; + void *md5_info; + void *rc4_info; - sha1_info = ssl_sha1_info_create(); - md5_info = ssl_md5_info_create(); - rc4_info = ssl_rc4_info_create(); - ssl_sha1_clear(sha1_info); - ssl_sha1_transform(sha1_info, update_key, key_len); - ssl_sha1_transform(sha1_info, (char*)g_pad_54, 40); - ssl_sha1_transform(sha1_info, key, key_len); - ssl_sha1_complete(sha1_info, shasig); - ssl_md5_clear(md5_info); - ssl_md5_transform(md5_info, update_key, key_len); - ssl_md5_transform(md5_info, (char*)g_pad_92, 48); - ssl_md5_transform(md5_info, shasig, 20); - ssl_md5_complete(md5_info, key); - ssl_rc4_set_key(rc4_info, key, key_len); - ssl_rc4_crypt(rc4_info, key, key_len); - if (key_len == 8) - { - xrdp_sec_make_40bit(key); - } - ssl_sha1_info_delete(sha1_info); - ssl_md5_info_delete(md5_info); - ssl_rc4_info_delete(rc4_info); - return 0; -} - -/*****************************************************************************/ -static void APP_CC -xrdp_sec_decrypt(struct xrdp_sec* self, char* data, int len) -{ - if (self->decrypt_use_count == 4096) - { - xrdp_sec_update(self->decrypt_key, self->decrypt_update_key, - self->rc4_key_len); - ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, - self->rc4_key_len); - self->decrypt_use_count = 0; - } - ssl_rc4_crypt(self->decrypt_rc4_info, data, len); - self->decrypt_use_count++; -} - -/*****************************************************************************/ -static void APP_CC -xrdp_sec_encrypt(struct xrdp_sec* self, char* data, int len) -{ - if (self->encrypt_use_count == 4096) - { - xrdp_sec_update(self->encrypt_key, self->encrypt_update_key, - self->rc4_key_len); - ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, - self->rc4_key_len); - self->encrypt_use_count = 0; - } - ssl_rc4_crypt(self->encrypt_rc4_info, data, len); - self->encrypt_use_count++; -} - -/*****************************************************************************/ -static int APP_CC -unicode_in(struct stream* s, int uni_len, char* dst, int dst_len) -{ - int dst_index; - int src_index; - - dst_index = 0; - src_index = 0; - while (src_index < uni_len) - { - if (dst_index >= dst_len || src_index > 512) - { - break; - } - in_uint8(s, dst[dst_index]); - in_uint8s(s, 1); - dst_index++; - src_index += 2; - } - in_uint8s(s, 2); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -xrdp_sec_process_logon_info(struct xrdp_sec* self, struct stream* s) -{ - int flags = 0; - int len_domain = 0; - int len_user = 0; - int len_password = 0; - int len_program = 0; - int len_directory = 0; - int len_ip = 0; - int len_dll = 0; - int tzone = 0; - char tmpdata[256]; - - /* initialize (zero out) local variables */ - g_memset(tmpdata,0,sizeof(char)*256); - in_uint8s(s, 4); - in_uint32_le(s, flags); - DEBUG(("in xrdp_sec_process_logon_info flags $%x", flags)); - /* this is the first test that the decrypt is working */ - if ((flags & RDP_LOGON_NORMAL) != RDP_LOGON_NORMAL) /* 0x33 */ - { /* must be or error */ - DEBUG(("xrdp_sec_process_logon_info: flags wrong, major error")); - return 1; - } - if (flags & RDP_LOGON_LEAVE_AUDIO) - { - self->rdp_layer->client_info.sound_code = 1; - DEBUG(("flag RDP_LOGON_LEAVE_AUDIO found")); - } - if ((flags & RDP_LOGON_AUTO) && (!self->rdp_layer->client_info.is_mce)) - /* todo, for now not allowing autologon and mce both */ - { - self->rdp_layer->client_info.rdp_autologin = 1; - DEBUG(("flag RDP_LOGON_AUTO found")); - } - if (flags & RDP_COMPRESSION) - { - self->rdp_layer->client_info.rdp_compression = 1; - DEBUG(("flag RDP_COMPRESSION found")); - } - in_uint16_le(s, len_domain); - if (len_domain > 511) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_domain > 511")); - return 1; - } - in_uint16_le(s, len_user); - if (len_user > 511) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_user > 511")); - return 1; - } - in_uint16_le(s, len_password); - if (len_password > 511) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_password > 511")); - return 1; - } - in_uint16_le(s, len_program); - if (len_program > 511) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_program > 511")); - return 1; - } - in_uint16_le(s, len_directory); - if (len_directory > 511) { - DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_directory > 511")); - return 1; - } - unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255); - DEBUG(("domain %s", self->rdp_layer->client_info.domain)); - unicode_in(s, len_user, self->rdp_layer->client_info.username, 255); - DEBUG(("username %s", self->rdp_layer->client_info.username)); - if (flags & RDP_LOGON_AUTO) - { - unicode_in(s, len_password, self->rdp_layer->client_info.password, 255); - DEBUG(("flag RDP_LOGON_AUTO found")); - } - else - { - in_uint8s(s, len_password + 2); - } - unicode_in(s, len_program, self->rdp_layer->client_info.program, 255); - DEBUG(("program %s", self->rdp_layer->client_info.program)); - unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255); - DEBUG(("directory %s", self->rdp_layer->client_info.directory)); - if (flags & RDP_LOGON_BLOB) - { - in_uint8s(s, 2); /* unknown */ - in_uint16_le(s, len_ip); - unicode_in(s, len_ip - 2, tmpdata, 255); - in_uint16_le(s, len_dll); - unicode_in(s, len_dll - 2, tmpdata, 255); - in_uint32_le(s, tzone); /* len of timetone */ - in_uint8s(s, 62); /* skip */ - in_uint8s(s, 22); /* skip misc. */ - in_uint8s(s, 62); /* skip */ - in_uint8s(s, 26); /* skip stuff */ - in_uint32_le(s, self->rdp_layer->client_info.rdp5_performanceflags); - } - DEBUG(("out xrdp_sec_process_logon_info")); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -xrdp_sec_send_lic_initial(struct xrdp_sec* self) -{ - struct stream* s = (struct stream *)NULL; - - make_stream(s); - init_stream(s, 8192); - if (xrdp_mcs_init(self->mcs_layer, s) != 0) - { - free_stream(s); - return 1; - } - out_uint8a(s, g_lic1, 322); - s_mark_end(s); - if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -xrdp_sec_send_lic_response(struct xrdp_sec* self) -{ - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (xrdp_mcs_init(self->mcs_layer, s) != 0) - { - free_stream(s); - return 1; - } - out_uint8a(s, g_lic2, 20); - s_mark_end(s); - if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -xrdp_sec_send_media_lic_response(struct xrdp_sec* self) -{ - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (xrdp_mcs_init(self->mcs_layer, s) != 0) - { - free_stream(s); - return 1; - } - out_uint8a(s, g_lic3, sizeof(g_lic3)); - s_mark_end(s); - if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -static void APP_CC -xrdp_sec_rsa_op(char* out, char* in, char* mod, char* exp) -{ - ssl_mod_exp(out, 64, in, 64, mod, 64, exp, 64); -} - -/*****************************************************************************/ -static void APP_CC -xrdp_sec_hash_48(char* out, char* in, char* salt1, char* salt2, int salt) -{ - int i; - void* sha1_info; - void* md5_info; - char pad[4]; - char sha1_sig[20]; - char md5_sig[16]; - - sha1_info = ssl_sha1_info_create(); - md5_info = ssl_md5_info_create(); - for (i = 0; i < 3; i++) - { - g_memset(pad, salt + i, 4); + sha1_info = ssl_sha1_info_create(); + md5_info = ssl_md5_info_create(); + rc4_info = ssl_rc4_info_create(); ssl_sha1_clear(sha1_info); - ssl_sha1_transform(sha1_info, pad, i + 1); - ssl_sha1_transform(sha1_info, in, 48); - ssl_sha1_transform(sha1_info, salt1, 32); - ssl_sha1_transform(sha1_info, salt2, 32); - ssl_sha1_complete(sha1_info, sha1_sig); + ssl_sha1_transform(sha1_info, update_key, key_len); + ssl_sha1_transform(sha1_info, (char *)g_pad_54, 40); + ssl_sha1_transform(sha1_info, key, key_len); + ssl_sha1_complete(sha1_info, shasig); ssl_md5_clear(md5_info); - ssl_md5_transform(md5_info, in, 48); - ssl_md5_transform(md5_info, sha1_sig, 20); - ssl_md5_complete(md5_info, md5_sig); - g_memcpy(out + i * 16, md5_sig, 16); - } - ssl_sha1_info_delete(sha1_info); - ssl_md5_info_delete(md5_info); + ssl_md5_transform(md5_info, update_key, key_len); + ssl_md5_transform(md5_info, (char *)g_pad_92, 48); + ssl_md5_transform(md5_info, shasig, 20); + ssl_md5_complete(md5_info, key); + ssl_rc4_set_key(rc4_info, key, key_len); + ssl_rc4_crypt(rc4_info, key, key_len); + + if (key_len == 8) + { + xrdp_sec_make_40bit(key); + } + + ssl_sha1_info_delete(sha1_info); + ssl_md5_info_delete(md5_info); + ssl_rc4_info_delete(rc4_info); + return 0; } /*****************************************************************************/ static void APP_CC -xrdp_sec_hash_16(char* out, char* in, char* salt1, char* salt2) +xrdp_sec_decrypt(struct xrdp_sec *self, char *data, int len) { - void* md5_info; + if (self->decrypt_use_count == 4096) + { + xrdp_sec_update(self->decrypt_key, self->decrypt_update_key, + self->rc4_key_len); + ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, + self->rc4_key_len); + self->decrypt_use_count = 0; + } - md5_info = ssl_md5_info_create(); - ssl_md5_clear(md5_info); - ssl_md5_transform(md5_info, in, 16); - ssl_md5_transform(md5_info, salt1, 32); - ssl_md5_transform(md5_info, salt2, 32); - ssl_md5_complete(md5_info, out); - ssl_md5_info_delete(md5_info); + ssl_rc4_crypt(self->decrypt_rc4_info, data, len); + self->decrypt_use_count++; } /*****************************************************************************/ static void APP_CC -xrdp_sec_establish_keys(struct xrdp_sec* self) +xrdp_sec_encrypt(struct xrdp_sec *self, char *data, int len) { - char session_key[48]; - char temp_hash[48]; - char input[48]; + if (self->encrypt_use_count == 4096) + { + xrdp_sec_update(self->encrypt_key, self->encrypt_update_key, + self->rc4_key_len); + ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, + self->rc4_key_len); + self->encrypt_use_count = 0; + } - g_memcpy(input, self->client_random, 24); - g_memcpy(input + 24, self->server_random, 24); - xrdp_sec_hash_48(temp_hash, input, self->client_random, - self->server_random, 65); - xrdp_sec_hash_48(session_key, temp_hash, self->client_random, - self->server_random, 88); - g_memcpy(self->sign_key, session_key, 16); - xrdp_sec_hash_16(self->encrypt_key, session_key + 16, self->client_random, - self->server_random); - xrdp_sec_hash_16(self->decrypt_key, session_key + 32, self->client_random, - self->server_random); - if (self->rc4_key_size == 1) - { - xrdp_sec_make_40bit(self->sign_key); - xrdp_sec_make_40bit(self->encrypt_key); - xrdp_sec_make_40bit(self->decrypt_key); - self->rc4_key_len = 8; - } - else - { - self->rc4_key_len = 16; - } - g_memcpy(self->decrypt_update_key, self->decrypt_key, 16); - g_memcpy(self->encrypt_update_key, self->encrypt_key, 16); - ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); - ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); + ssl_rc4_crypt(self->encrypt_rc4_info, data, len); + self->encrypt_use_count++; +} + +/*****************************************************************************/ +static int APP_CC +unicode_in(struct stream *s, int uni_len, char *dst, int dst_len) +{ + int dst_index; + int src_index; + + dst_index = 0; + src_index = 0; + + while (src_index < uni_len) + { + if (dst_index >= dst_len || src_index > 512) + { + break; + } + + in_uint8(s, dst[dst_index]); + in_uint8s(s, 1); + dst_index++; + src_index += 2; + } + + in_uint8s(s, 2); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s) +{ + int flags = 0; + int len_domain = 0; + int len_user = 0; + int len_password = 0; + int len_program = 0; + int len_directory = 0; + int len_ip = 0; + int len_dll = 0; + int tzone = 0; + char tmpdata[256]; + + /* initialize (zero out) local variables */ + g_memset(tmpdata, 0, sizeof(char) * 256); + in_uint8s(s, 4); + in_uint32_le(s, flags); + DEBUG(("in xrdp_sec_process_logon_info flags $%x", flags)); + + /* this is the first test that the decrypt is working */ + if ((flags & RDP_LOGON_NORMAL) != RDP_LOGON_NORMAL) /* 0x33 */ + { + /* must be or error */ + DEBUG(("xrdp_sec_process_logon_info: flags wrong, major error")); + return 1; + } + + if (flags & RDP_LOGON_LEAVE_AUDIO) + { + self->rdp_layer->client_info.sound_code = 1; + DEBUG(("flag RDP_LOGON_LEAVE_AUDIO found")); + } + + if ((flags & RDP_LOGON_AUTO) && (!self->rdp_layer->client_info.is_mce)) + /* todo, for now not allowing autologon and mce both */ + { + self->rdp_layer->client_info.rdp_autologin = 1; + DEBUG(("flag RDP_LOGON_AUTO found")); + } + + if (flags & RDP_COMPRESSION) + { + self->rdp_layer->client_info.rdp_compression = 1; + DEBUG(("flag RDP_COMPRESSION found")); + } + + in_uint16_le(s, len_domain); + + if (len_domain > 511) + { + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_domain > 511")); + return 1; + } + + in_uint16_le(s, len_user); + + if (len_user > 511) + { + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_user > 511")); + return 1; + } + + in_uint16_le(s, len_password); + + if (len_password > 511) + { + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_password > 511")); + return 1; + } + + in_uint16_le(s, len_program); + + if (len_program > 511) + { + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_program > 511")); + return 1; + } + + in_uint16_le(s, len_directory); + + if (len_directory > 511) + { + DEBUG(("ERROR [xrdp_sec_process_logon_info()]: len_directory > 511")); + return 1; + } + + unicode_in(s, len_domain, self->rdp_layer->client_info.domain, 255); + DEBUG(("domain %s", self->rdp_layer->client_info.domain)); + unicode_in(s, len_user, self->rdp_layer->client_info.username, 255); + DEBUG(("username %s", self->rdp_layer->client_info.username)); + + if (flags & RDP_LOGON_AUTO) + { + unicode_in(s, len_password, self->rdp_layer->client_info.password, 255); + DEBUG(("flag RDP_LOGON_AUTO found")); + } + else + { + in_uint8s(s, len_password + 2); + } + + unicode_in(s, len_program, self->rdp_layer->client_info.program, 255); + DEBUG(("program %s", self->rdp_layer->client_info.program)); + unicode_in(s, len_directory, self->rdp_layer->client_info.directory, 255); + DEBUG(("directory %s", self->rdp_layer->client_info.directory)); + + if (flags & RDP_LOGON_BLOB) + { + in_uint8s(s, 2); /* unknown */ + in_uint16_le(s, len_ip); + unicode_in(s, len_ip - 2, tmpdata, 255); + in_uint16_le(s, len_dll); + unicode_in(s, len_dll - 2, tmpdata, 255); + in_uint32_le(s, tzone); /* len of timetone */ + in_uint8s(s, 62); /* skip */ + in_uint8s(s, 22); /* skip misc. */ + in_uint8s(s, 62); /* skip */ + in_uint8s(s, 26); /* skip stuff */ + in_uint32_le(s, self->rdp_layer->client_info.rdp5_performanceflags); + } + + DEBUG(("out xrdp_sec_process_logon_info")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_sec_send_lic_initial(struct xrdp_sec *self) +{ + struct stream *s = (struct stream *)NULL; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_mcs_init(self->mcs_layer, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint8a(s, g_lic1, 322); + s_mark_end(s); + + if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_sec_send_lic_response(struct xrdp_sec *self) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_mcs_init(self->mcs_layer, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint8a(s, g_lic2, 20); + s_mark_end(s); + + if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +xrdp_sec_send_media_lic_response(struct xrdp_sec *self) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (xrdp_mcs_init(self->mcs_layer, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint8a(s, g_lic3, sizeof(g_lic3)); + s_mark_end(s); + + if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_rsa_op(char *out, char *in, char *mod, char *exp) +{ + ssl_mod_exp(out, 64, in, 64, mod, 64, exp, 64); +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_hash_48(char *out, char *in, char *salt1, char *salt2, int salt) +{ + int i; + void *sha1_info; + void *md5_info; + char pad[4]; + char sha1_sig[20]; + char md5_sig[16]; + + sha1_info = ssl_sha1_info_create(); + md5_info = ssl_md5_info_create(); + + for (i = 0; i < 3; i++) + { + g_memset(pad, salt + i, 4); + ssl_sha1_clear(sha1_info); + ssl_sha1_transform(sha1_info, pad, i + 1); + ssl_sha1_transform(sha1_info, in, 48); + ssl_sha1_transform(sha1_info, salt1, 32); + ssl_sha1_transform(sha1_info, salt2, 32); + ssl_sha1_complete(sha1_info, sha1_sig); + ssl_md5_clear(md5_info); + ssl_md5_transform(md5_info, in, 48); + ssl_md5_transform(md5_info, sha1_sig, 20); + ssl_md5_complete(md5_info, md5_sig); + g_memcpy(out + i * 16, md5_sig, 16); + } + + ssl_sha1_info_delete(sha1_info); + ssl_md5_info_delete(md5_info); +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_hash_16(char *out, char *in, char *salt1, char *salt2) +{ + void *md5_info; + + md5_info = ssl_md5_info_create(); + ssl_md5_clear(md5_info); + ssl_md5_transform(md5_info, in, 16); + ssl_md5_transform(md5_info, salt1, 32); + ssl_md5_transform(md5_info, salt2, 32); + ssl_md5_complete(md5_info, out); + ssl_md5_info_delete(md5_info); +} + +/*****************************************************************************/ +static void APP_CC +xrdp_sec_establish_keys(struct xrdp_sec *self) +{ + char session_key[48]; + char temp_hash[48]; + char input[48]; + + g_memcpy(input, self->client_random, 24); + g_memcpy(input + 24, self->server_random, 24); + xrdp_sec_hash_48(temp_hash, input, self->client_random, + self->server_random, 65); + xrdp_sec_hash_48(session_key, temp_hash, self->client_random, + self->server_random, 88); + g_memcpy(self->sign_key, session_key, 16); + xrdp_sec_hash_16(self->encrypt_key, session_key + 16, self->client_random, + self->server_random); + xrdp_sec_hash_16(self->decrypt_key, session_key + 32, self->client_random, + self->server_random); + + if (self->rc4_key_size == 1) + { + xrdp_sec_make_40bit(self->sign_key); + xrdp_sec_make_40bit(self->encrypt_key); + xrdp_sec_make_40bit(self->decrypt_key); + self->rc4_key_len = 8; + } + else + { + self->rc4_key_len = 16; + } + + g_memcpy(self->decrypt_update_key, self->decrypt_key, 16); + g_memcpy(self->encrypt_update_key, self->encrypt_key, 16); + ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); + ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_sec_recv(struct xrdp_sec* self, struct stream* s, int* chan) +xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan) { - int flags; - int len; + int flags; + int len; - DEBUG((" in xrdp_sec_recv")); - if (xrdp_mcs_recv(self->mcs_layer, s, chan) != 0) - { - DEBUG((" out xrdp_sec_recv error")); - return 1; - } - in_uint32_le(s, flags); - DEBUG((" in xrdp_sec_recv flags $%x", flags)); - if (flags & SEC_ENCRYPT) /* 0x08 */ - { - in_uint8s(s, 8); /* signature */ - xrdp_sec_decrypt(self, s->p, (int)(s->end - s->p)); - } - if (flags & SEC_CLIENT_RANDOM) /* 0x01 */ - { - in_uint32_le(s, len); - in_uint8a(s, self->client_crypt_random, 64); - xrdp_sec_rsa_op(self->client_random, self->client_crypt_random, - self->pub_mod, self->pri_exp); - xrdp_sec_establish_keys(self); - *chan = 1; /* just set a non existing channel and exit */ - DEBUG((" out xrdp_sec_recv")); - return 0; - } - if (flags & SEC_LOGON_INFO) /* 0x40 */ - { - if (xrdp_sec_process_logon_info(self, s) != 0) + DEBUG((" in xrdp_sec_recv")); + + if (xrdp_mcs_recv(self->mcs_layer, s, chan) != 0) { - DEBUG((" out xrdp_sec_recv error")); - return 1; - } - if (self->rdp_layer->client_info.is_mce) - { - if (xrdp_sec_send_media_lic_response(self) != 0) - { DEBUG((" out xrdp_sec_recv error")); return 1; - } - DEBUG((" out xrdp_sec_recv")); - return -1; /* special error that means send demand active */ } - if (xrdp_sec_send_lic_initial(self) != 0) + + in_uint32_le(s, flags); + DEBUG((" in xrdp_sec_recv flags $%x", flags)); + + if (flags & SEC_ENCRYPT) /* 0x08 */ { - DEBUG((" out xrdp_sec_recv error")); - return 1; + in_uint8s(s, 8); /* signature */ + xrdp_sec_decrypt(self, s->p, (int)(s->end - s->p)); } - *chan = 1; /* just set a non existing channel and exit */ + + if (flags & SEC_CLIENT_RANDOM) /* 0x01 */ + { + in_uint32_le(s, len); + in_uint8a(s, self->client_crypt_random, 64); + xrdp_sec_rsa_op(self->client_random, self->client_crypt_random, + self->pub_mod, self->pri_exp); + xrdp_sec_establish_keys(self); + *chan = 1; /* just set a non existing channel and exit */ + DEBUG((" out xrdp_sec_recv")); + return 0; + } + + if (flags & SEC_LOGON_INFO) /* 0x40 */ + { + if (xrdp_sec_process_logon_info(self, s) != 0) + { + DEBUG((" out xrdp_sec_recv error")); + return 1; + } + + if (self->rdp_layer->client_info.is_mce) + { + if (xrdp_sec_send_media_lic_response(self) != 0) + { + DEBUG((" out xrdp_sec_recv error")); + return 1; + } + + DEBUG((" out xrdp_sec_recv")); + return -1; /* special error that means send demand active */ + } + + if (xrdp_sec_send_lic_initial(self) != 0) + { + DEBUG((" out xrdp_sec_recv error")); + return 1; + } + + *chan = 1; /* just set a non existing channel and exit */ + DEBUG((" out xrdp_sec_recv")); + return 0; + } + + if (flags & SEC_LICENCE_NEG) /* 0x80 */ + { + if (xrdp_sec_send_lic_response(self) != 0) + { + DEBUG((" out xrdp_sec_recv error")); + return 1; + } + + DEBUG((" out xrdp_sec_recv")); + return -1; /* special error that means send demand active */ + } + DEBUG((" out xrdp_sec_recv")); return 0; - } - if (flags & SEC_LICENCE_NEG) /* 0x80 */ - { - if (xrdp_sec_send_lic_response(self) != 0) - { - DEBUG((" out xrdp_sec_recv error")); - return 1; - } - DEBUG((" out xrdp_sec_recv")); - return -1; /* special error that means send demand active */ - } - DEBUG((" out xrdp_sec_recv")); - return 0; } /*****************************************************************************/ /* Output a uint32 into a buffer (little-endian) */ static void -buf_out_uint32(char* buffer, int value) +buf_out_uint32(char *buffer, int value) { - buffer[0] = (value) & 0xff; - buffer[1] = (value >> 8) & 0xff; - buffer[2] = (value >> 16) & 0xff; - buffer[3] = (value >> 24) & 0xff; + 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 */ static void APP_CC -xrdp_sec_sign(struct xrdp_sec* self, char* out, int out_len, - char* data, int data_len) +xrdp_sec_sign(struct xrdp_sec *self, char *out, int out_len, + char *data, int data_len) { - char shasig[20]; - char md5sig[16]; - char lenhdr[4]; - void* sha1_info; - void* md5_info; + char shasig[20]; + char md5sig[16]; + char lenhdr[4]; + void *sha1_info; + void *md5_info; - buf_out_uint32(lenhdr, data_len); - sha1_info = ssl_sha1_info_create(); - md5_info = ssl_md5_info_create(); - ssl_sha1_clear(sha1_info); - ssl_sha1_transform(sha1_info, self->sign_key, self->rc4_key_len); - ssl_sha1_transform(sha1_info, (char*)g_pad_54, 40); - ssl_sha1_transform(sha1_info, lenhdr, 4); - ssl_sha1_transform(sha1_info, data, data_len); - ssl_sha1_complete(sha1_info, shasig); - ssl_md5_clear(md5_info); - ssl_md5_transform(md5_info, self->sign_key, self->rc4_key_len); - ssl_md5_transform(md5_info, (char*)g_pad_92, 48); - ssl_md5_transform(md5_info, shasig, 20); - ssl_md5_complete(md5_info, md5sig); - g_memcpy(out, md5sig, out_len); - ssl_sha1_info_delete(sha1_info); - ssl_md5_info_delete(md5_info); + buf_out_uint32(lenhdr, data_len); + sha1_info = ssl_sha1_info_create(); + md5_info = ssl_md5_info_create(); + ssl_sha1_clear(sha1_info); + ssl_sha1_transform(sha1_info, self->sign_key, self->rc4_key_len); + ssl_sha1_transform(sha1_info, (char *)g_pad_54, 40); + ssl_sha1_transform(sha1_info, lenhdr, 4); + ssl_sha1_transform(sha1_info, data, data_len); + ssl_sha1_complete(sha1_info, shasig); + ssl_md5_clear(md5_info); + ssl_md5_transform(md5_info, self->sign_key, self->rc4_key_len); + ssl_md5_transform(md5_info, (char *)g_pad_92, 48); + ssl_md5_transform(md5_info, shasig, 20); + ssl_md5_complete(md5_info, md5sig); + g_memcpy(out, md5sig, out_len); + ssl_sha1_info_delete(sha1_info); + ssl_md5_info_delete(md5_info); } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_sec_send(struct xrdp_sec* self, struct stream* s, int chan) +xrdp_sec_send(struct xrdp_sec *self, struct stream *s, int chan) { - int datalen; + int datalen; - DEBUG((" in xrdp_sec_send")); - s_pop_layer(s, sec_hdr); - if (self->crypt_level > 1) - { - out_uint32_le(s, SEC_ENCRYPT); - datalen = (int)((s->end - s->p) - 8); - xrdp_sec_sign(self, s->p, 8, s->p + 8, datalen); - xrdp_sec_encrypt(self, s->p + 8, datalen); - } - else - { - out_uint32_le(s, 0); - } - if (xrdp_mcs_send(self->mcs_layer, s, chan) != 0) - { - return 1; - } - DEBUG((" out xrdp_sec_send")); - return 0; + DEBUG((" in xrdp_sec_send")); + s_pop_layer(s, sec_hdr); + + if (self->crypt_level > 1) + { + out_uint32_le(s, SEC_ENCRYPT); + datalen = (int)((s->end - s->p) - 8); + xrdp_sec_sign(self, s->p, 8, s->p + 8, datalen); + xrdp_sec_encrypt(self, s->p + 8, datalen); + } + else + { + out_uint32_le(s, 0); + } + + if (xrdp_mcs_send(self->mcs_layer, s, chan) != 0) + { + return 1; + } + + DEBUG((" out xrdp_sec_send")); + return 0; } /*****************************************************************************/ /* this adds the mcs channels in the list of channels to be used when creating the server mcs data */ static int APP_CC -xrdp_sec_process_mcs_data_channels(struct xrdp_sec* self, struct stream* s) +xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) { - int num_channels; - int index; - struct mcs_channel_item* channel_item; + int num_channels; + int index; + struct mcs_channel_item *channel_item; + + DEBUG(("processing channels, channel_code is %d", self->channel_code)); + + /* this is an option set in xrdp.ini */ + if (self->channel_code != 1) /* are channels on? */ + { + g_writeln("Processing channel data from client - The channel is off"); + return 0; + } + + in_uint32_le(s, num_channels); + + for (index = 0; index < num_channels; index++) + { + channel_item = (struct mcs_channel_item *) + g_malloc(sizeof(struct mcs_channel_item), 1); + in_uint8a(s, channel_item->name, 8); + in_uint32_le(s, channel_item->flags); + channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1); + list_add_item(self->mcs_layer->channel_list, (long)channel_item); + DEBUG(("got channel flags %8.8x name %s", channel_item->flags, + channel_item->name)); + } - DEBUG(("processing channels, channel_code is %d", self->channel_code)); - /* this is an option set in xrdp.ini */ - if (self->channel_code != 1) /* are channels on? */ - { - g_writeln("Processing channel data from client - The channel is off"); return 0; - } - in_uint32_le(s, num_channels); - for (index = 0; index < num_channels; index++) - { - channel_item = (struct mcs_channel_item*) - g_malloc(sizeof(struct mcs_channel_item), 1); - in_uint8a(s, channel_item->name, 8); - in_uint32_le(s, channel_item->flags); - channel_item->chanid = MCS_GLOBAL_CHANNEL + (index + 1); - list_add_item(self->mcs_layer->channel_list, (long)channel_item); - DEBUG(("got channel flags %8.8x name %s", channel_item->flags, - channel_item->name)); - } - return 0; } /*****************************************************************************/ /* process client mcs data, we need some things in here to create the server mcs data */ int APP_CC -xrdp_sec_process_mcs_data(struct xrdp_sec* self) +xrdp_sec_process_mcs_data(struct xrdp_sec *self) { - struct stream* s = (struct stream *)NULL; - char* hold_p = (char *)NULL; - int tag = 0; - int size = 0; + struct stream *s = (struct stream *)NULL; + char *hold_p = (char *)NULL; + int tag = 0; + int size = 0; - s = &self->client_mcs_data; - /* set p to beginning */ - s->p = s->data; - /* skip header */ - in_uint8s(s, 23); - while (s_check_rem(s, 4)) - { - hold_p = s->p; - in_uint16_le(s, tag); - in_uint16_le(s, size); - if (size < 4 || !s_check_rem(s, size - 4)) + s = &self->client_mcs_data; + /* set p to beginning */ + s->p = s->data; + /* skip header */ + in_uint8s(s, 23); + + while (s_check_rem(s, 4)) { - g_writeln("error in xrdp_sec_process_mcs_data tag %d size %d", - tag, size); - break; + hold_p = s->p; + in_uint16_le(s, tag); + in_uint16_le(s, size); + + if (size < 4 || !s_check_rem(s, size - 4)) + { + g_writeln("error in xrdp_sec_process_mcs_data tag %d size %d", + tag, size); + break; + } + + switch (tag) + { + case SEC_TAG_CLI_INFO: + break; + case SEC_TAG_CLI_CRYPT: + break; + case SEC_TAG_CLI_CHANNELS: + xrdp_sec_process_mcs_data_channels(self, s); + break; + case SEC_TAG_CLI_4: + break; + default: + g_writeln("error unknown xrdp_sec_process_mcs_data tag %d size %d", + tag, size); + break; + } + + s->p = hold_p + size; } - switch (tag) - { - case SEC_TAG_CLI_INFO: - break; - case SEC_TAG_CLI_CRYPT: - break; - case SEC_TAG_CLI_CHANNELS: - xrdp_sec_process_mcs_data_channels(self, s); - break; - case SEC_TAG_CLI_4: - break; - default: - g_writeln("error unknown xrdp_sec_process_mcs_data tag %d size %d", - tag, size); - break; - } - s->p = hold_p + size; - } - /* set p to beginning */ - s->p = s->data; - return 0; + + /* set p to beginning */ + s->p = s->data; + return 0; } /*****************************************************************************/ /* prepare server mcs data to send in mcs layer */ int APP_CC -xrdp_sec_out_mcs_data(struct xrdp_sec* self) +xrdp_sec_out_mcs_data(struct xrdp_sec *self) { - struct stream* s; - int num_channels_even; - int num_channels; - int index; - int channel; + struct stream *s; + int num_channels_even; + int num_channels; + int index; + int channel; - num_channels = self->mcs_layer->channel_list->count; - num_channels_even = num_channels + (num_channels & 1); - s = &self->server_mcs_data; - init_stream(s, 512); - out_uint16_be(s, 5); - out_uint16_be(s, 0x14); - out_uint8(s, 0x7c); - out_uint16_be(s, 1); - out_uint8(s, 0x2a); - out_uint8(s, 0x14); - out_uint8(s, 0x76); - out_uint8(s, 0x0a); - out_uint8(s, 1); - out_uint8(s, 1); - out_uint8(s, 0); - out_uint16_le(s, 0xc001); - out_uint8(s, 0); - out_uint8(s, 0x4d); /* M */ - out_uint8(s, 0x63); /* c */ - out_uint8(s, 0x44); /* D */ - out_uint8(s, 0x6e); /* n */ - out_uint16_be(s, 0x80fc + (num_channels_even * 2)); - out_uint16_le(s, SEC_TAG_SRV_INFO); - out_uint16_le(s, 8); /* len */ - out_uint8(s, 4); /* 4 = rdp5 1 = rdp4 */ - out_uint8(s, 0); - out_uint8(s, 8); - out_uint8(s, 0); - out_uint16_le(s, SEC_TAG_SRV_CHANNELS); - out_uint16_le(s, 8 + (num_channels_even * 2)); /* len */ - out_uint16_le(s, MCS_GLOBAL_CHANNEL); /* 1003, 0x03eb main channel */ - out_uint16_le(s, num_channels); /* number of other channels */ - for (index = 0; index < num_channels_even; index++) - { - if (index < num_channels) + num_channels = self->mcs_layer->channel_list->count; + num_channels_even = num_channels + (num_channels & 1); + s = &self->server_mcs_data; + init_stream(s, 512); + out_uint16_be(s, 5); + out_uint16_be(s, 0x14); + out_uint8(s, 0x7c); + out_uint16_be(s, 1); + out_uint8(s, 0x2a); + out_uint8(s, 0x14); + out_uint8(s, 0x76); + out_uint8(s, 0x0a); + out_uint8(s, 1); + out_uint8(s, 1); + out_uint8(s, 0); + out_uint16_le(s, 0xc001); + out_uint8(s, 0); + out_uint8(s, 0x4d); /* M */ + out_uint8(s, 0x63); /* c */ + out_uint8(s, 0x44); /* D */ + out_uint8(s, 0x6e); /* n */ + out_uint16_be(s, 0x80fc + (num_channels_even * 2)); + out_uint16_le(s, SEC_TAG_SRV_INFO); + out_uint16_le(s, 8); /* len */ + out_uint8(s, 4); /* 4 = rdp5 1 = rdp4 */ + out_uint8(s, 0); + out_uint8(s, 8); + out_uint8(s, 0); + out_uint16_le(s, SEC_TAG_SRV_CHANNELS); + out_uint16_le(s, 8 + (num_channels_even * 2)); /* len */ + out_uint16_le(s, MCS_GLOBAL_CHANNEL); /* 1003, 0x03eb main channel */ + out_uint16_le(s, num_channels); /* number of other channels */ + + for (index = 0; index < num_channels_even; index++) { - channel = MCS_GLOBAL_CHANNEL + (index + 1); - out_uint16_le(s, channel); + if (index < num_channels) + { + channel = MCS_GLOBAL_CHANNEL + (index + 1); + out_uint16_le(s, channel); + } + else + { + out_uint16_le(s, 0); + } } - else - { - out_uint16_le(s, 0); - } - } - out_uint16_le(s, SEC_TAG_SRV_CRYPT); - out_uint16_le(s, 0x00ec); /* len is 236 */ - out_uint32_le(s, self->rc4_key_size); /* key len 1 = 40 bit 2 = 128 bit */ - out_uint32_le(s, self->crypt_level); /* crypt level 1 = low 2 = medium */ - /* 3 = high */ - out_uint32_le(s, 32); /* 32 bytes random len */ - out_uint32_le(s, 0xb8); /* 184 bytes rsa info(certificate) len */ - out_uint8a(s, self->server_random, 32); - /* here to end is certificate */ - /* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ */ - /* TermService\Parameters\Certificate */ - out_uint32_le(s, 1); - out_uint32_le(s, 1); - out_uint32_le(s, 1); - out_uint16_le(s, SEC_TAG_PUBKEY); - out_uint16_le(s, 0x005c); /* 92 bytes length of SEC_TAG_PUBKEY */ - out_uint32_le(s, SEC_RSA_MAGIC); - out_uint32_le(s, 0x48); /* 72 bytes modulus len */ - out_uint32_be(s, 0x00020000); - out_uint32_be(s, 0x3f000000); - out_uint8a(s, self->pub_exp, 4); /* pub exp */ - out_uint8a(s, self->pub_mod, 64); /* pub mod */ - out_uint8s(s, 8); /* pad */ - out_uint16_le(s, SEC_TAG_KEYSIG); - out_uint16_le(s, 72); /* len */ - out_uint8a(s, self->pub_sig, 64); /* pub sig */ - out_uint8s(s, 8); /* pad */ - /* end certificate */ - s_mark_end(s); - return 0; + + out_uint16_le(s, SEC_TAG_SRV_CRYPT); + out_uint16_le(s, 0x00ec); /* len is 236 */ + out_uint32_le(s, self->rc4_key_size); /* key len 1 = 40 bit 2 = 128 bit */ + out_uint32_le(s, self->crypt_level); /* crypt level 1 = low 2 = medium */ + /* 3 = high */ + out_uint32_le(s, 32); /* 32 bytes random len */ + out_uint32_le(s, 0xb8); /* 184 bytes rsa info(certificate) len */ + out_uint8a(s, self->server_random, 32); + /* here to end is certificate */ + /* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ */ + /* TermService\Parameters\Certificate */ + out_uint32_le(s, 1); + out_uint32_le(s, 1); + out_uint32_le(s, 1); + out_uint16_le(s, SEC_TAG_PUBKEY); + out_uint16_le(s, 0x005c); /* 92 bytes length of SEC_TAG_PUBKEY */ + out_uint32_le(s, SEC_RSA_MAGIC); + out_uint32_le(s, 0x48); /* 72 bytes modulus len */ + out_uint32_be(s, 0x00020000); + out_uint32_be(s, 0x3f000000); + out_uint8a(s, self->pub_exp, 4); /* pub exp */ + out_uint8a(s, self->pub_mod, 64); /* pub mod */ + out_uint8s(s, 8); /* pad */ + out_uint16_le(s, SEC_TAG_KEYSIG); + out_uint16_le(s, 72); /* len */ + out_uint8a(s, self->pub_sig, 64); /* pub sig */ + out_uint8s(s, 8); /* pad */ + /* end certificate */ + s_mark_end(s); + return 0; } /*****************************************************************************/ /* process the mcs client data we received from the mcs layer */ static void APP_CC -xrdp_sec_in_mcs_data(struct xrdp_sec* self) +xrdp_sec_in_mcs_data(struct xrdp_sec *self) { - struct stream* s = (struct stream *)NULL; - struct xrdp_client_info* client_info = (struct xrdp_client_info *)NULL; - int index = 0; - char c = 0; + struct stream *s = (struct stream *)NULL; + struct xrdp_client_info *client_info = (struct xrdp_client_info *)NULL; + int index = 0; + char c = 0; - client_info = &(self->rdp_layer->client_info); - s = &(self->client_mcs_data); - /* get hostname, its unicode */ - s->p = s->data; - in_uint8s(s, 47); - g_memset(client_info->hostname, 0, 32); - c = 1; - index = 0; - while (index < 16 && c != 0) - { - in_uint8(s, c); - in_uint8s(s, 1); - client_info->hostname[index] = c; - index++; - } - /* get build */ - s->p = s->data; - in_uint8s(s, 43); - in_uint32_le(s, client_info->build); - /* get keylayout */ - s->p = s->data; - in_uint8s(s, 39); - in_uint32_le(s, client_info->keylayout); - s->p = s->data; + client_info = &(self->rdp_layer->client_info); + s = &(self->client_mcs_data); + /* get hostname, its unicode */ + s->p = s->data; + in_uint8s(s, 47); + g_memset(client_info->hostname, 0, 32); + c = 1; + index = 0; + + while (index < 16 && c != 0) + { + in_uint8(s, c); + in_uint8s(s, 1); + client_info->hostname[index] = c; + index++; + } + + /* get build */ + s->p = s->data; + in_uint8s(s, 43); + in_uint32_le(s, client_info->build); + /* get keylayout */ + s->p = s->data; + in_uint8s(s, 39); + in_uint32_le(s, client_info->keylayout); + s->p = s->data; } /*****************************************************************************/ int APP_CC -xrdp_sec_incoming(struct xrdp_sec* self) +xrdp_sec_incoming(struct xrdp_sec *self) { - struct list* items = NULL; - struct list* values = NULL; - int index = 0; - char* item = NULL; - char* value = NULL; - char key_file[256]; + struct list *items = NULL; + struct list *values = NULL; + int index = 0; + char *item = NULL; + char *value = NULL; + char key_file[256]; - g_memset(key_file,0,sizeof(char)*256); + g_memset(key_file, 0, sizeof(char) * 256); + + DEBUG((" in xrdp_sec_incoming")); + g_random(self->server_random, 32); + items = list_create(); + items->auto_free = 1; + values = list_create(); + values->auto_free = 1; + g_snprintf(key_file, 255, "%s/rsakeys.ini", XRDP_CFG_PATH); + + if (file_by_name_read_section(key_file, "keys", items, values) != 0) + { + /* this is a show stopper */ + g_writeln("xrdp_sec_incoming: error reading %s file", key_file); + list_delete(items); + list_delete(values); + return 1; + } + + for (index = 0; index < items->count; index++) + { + item = (char *)list_get_item(items, index); + value = (char *)list_get_item(values, index); + + if (g_strcasecmp(item, "pub_exp") == 0) + { + hex_str_to_bin(value, self->pub_exp, 4); + } + else if (g_strcasecmp(item, "pub_mod") == 0) + { + hex_str_to_bin(value, self->pub_mod, 64); + } + else if (g_strcasecmp(item, "pub_sig") == 0) + { + hex_str_to_bin(value, self->pub_sig, 64); + } + else if (g_strcasecmp(item, "pri_exp") == 0) + { + hex_str_to_bin(value, self->pri_exp, 64); + } + } - DEBUG((" in xrdp_sec_incoming")); - g_random(self->server_random, 32); - items = list_create(); - items->auto_free = 1; - values = list_create(); - values->auto_free = 1; - g_snprintf(key_file, 255, "%s/rsakeys.ini", XRDP_CFG_PATH); - if (file_by_name_read_section(key_file, "keys", items, values) != 0) - { - /* this is a show stopper */ - g_writeln("xrdp_sec_incoming: error reading %s file", key_file); list_delete(items); list_delete(values); - return 1; - } - for (index = 0; index < items->count; index++) - { - item = (char*)list_get_item(items, index); - value = (char*)list_get_item(values, index); - if (g_strcasecmp(item, "pub_exp") == 0) + + if (xrdp_mcs_incoming(self->mcs_layer) != 0) { - hex_str_to_bin(value, self->pub_exp, 4); + return 1; } - else if (g_strcasecmp(item, "pub_mod") == 0) - { - hex_str_to_bin(value, self->pub_mod, 64); - } - else if (g_strcasecmp(item, "pub_sig") == 0) - { - hex_str_to_bin(value, self->pub_sig, 64); - } - else if (g_strcasecmp(item, "pri_exp") == 0) - { - hex_str_to_bin(value, self->pri_exp, 64); - } - } - list_delete(items); - list_delete(values); - if (xrdp_mcs_incoming(self->mcs_layer) != 0) - { - return 1; - } + #ifdef XRDP_DEBUG - g_writeln("client mcs data received"); - g_hexdump(self->client_mcs_data.data, - (int)(self->client_mcs_data.end - self->client_mcs_data.data)); - g_writeln("server mcs data sent"); - g_hexdump(self->server_mcs_data.data, - (int)(self->server_mcs_data.end - self->server_mcs_data.data)); + g_writeln("client mcs data received"); + g_hexdump(self->client_mcs_data.data, + (int)(self->client_mcs_data.end - self->client_mcs_data.data)); + g_writeln("server mcs data sent"); + g_hexdump(self->server_mcs_data.data, + (int)(self->server_mcs_data.end - self->server_mcs_data.data)); #endif - DEBUG((" out xrdp_sec_incoming")); - xrdp_sec_in_mcs_data(self); - return 0; + DEBUG((" out xrdp_sec_incoming")); + xrdp_sec_in_mcs_data(self); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_sec_disconnect(struct xrdp_sec* self) +xrdp_sec_disconnect(struct xrdp_sec *self) { - int rv; + int rv; - DEBUG((" in xrdp_sec_disconnect")); - rv = xrdp_mcs_disconnect(self->mcs_layer); - DEBUG((" out xrdp_sec_disconnect")); - return rv; + DEBUG((" in xrdp_sec_disconnect")); + rv = xrdp_mcs_disconnect(self->mcs_layer); + DEBUG((" out xrdp_sec_disconnect")); + return rv; } diff --git a/libxrdp/xrdp_surface.c b/libxrdp/xrdp_surface.c index efc640ee..34ab9f48 100644 --- a/libxrdp/xrdp_surface.c +++ b/libxrdp/xrdp_surface.c @@ -21,141 +21,144 @@ #include "freerdp/codec/rfx.h" /*****************************************************************************/ -struct xrdp_surface* APP_CC -xrdp_surface_create(struct xrdp_session* session, struct xrdp_fastpath* fastpath) +struct xrdp_surface *APP_CC +xrdp_surface_create(struct xrdp_session *session, struct xrdp_fastpath *fastpath) { - struct xrdp_surface* self; + struct xrdp_surface *self; - self = (struct xrdp_surface*)g_malloc(sizeof(struct xrdp_surface), 1); - self->session = session; - self->fastpath = fastpath; - self->rfx_context = rfx_context_new(); - self->s = stream_new(16384); - return self; + self = (struct xrdp_surface *)g_malloc(sizeof(struct xrdp_surface), 1); + self->session = session; + self->fastpath = fastpath; + self->rfx_context = rfx_context_new(); + self->s = stream_new(16384); + return self; } /*****************************************************************************/ void APP_CC -xrdp_surface_delete(struct xrdp_surface* self) +xrdp_surface_delete(struct xrdp_surface *self) { - STREAM* s; - RFX_CONTEXT* rfx_context; + STREAM *s; + RFX_CONTEXT *rfx_context; - if (self == 0) - { - return; - } - s = (STREAM*)(self->s); - rfx_context = (RFX_CONTEXT*)(self->rfx_context); - free_stream(self->out_s); - stream_free(s); - rfx_context_free(rfx_context); - g_free(self); + if (self == 0) + { + return; + } + + s = (STREAM *)(self->s); + rfx_context = (RFX_CONTEXT *)(self->rfx_context); + free_stream(self->out_s); + stream_free(s); + rfx_context_free(rfx_context); + g_free(self); } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_surface_reset(struct xrdp_surface* self) +xrdp_surface_reset(struct xrdp_surface *self) { - return 0; + return 0; } /*****************************************************************************/ int APP_CC -xrdp_surface_init(struct xrdp_surface* self) +xrdp_surface_init(struct xrdp_surface *self) { - int width; - int height; - RFX_CONTEXT* rfx_context; + int width; + int height; + RFX_CONTEXT *rfx_context; - rfx_context = (RFX_CONTEXT*)(self->rfx_context); - width = self->session->client_info->width; - height= self->session->client_info->height; + rfx_context = (RFX_CONTEXT *)(self->rfx_context); + width = self->session->client_info->width; + height = self->session->client_info->height; - rfx_context->mode = self->session->client_info->rfx_entropy; - rfx_context->width = width; - rfx_context->height= height; + rfx_context->mode = self->session->client_info->rfx_entropy; + rfx_context->width = width; + rfx_context->height = height; - make_stream(self->out_s); - init_stream(self->out_s, 2 * 3 * width * height + 22); + make_stream(self->out_s); + init_stream(self->out_s, 2 * 3 * width * height + 22); - return 0; + return 0; } /*****************************************************************************/ int APP_CC -xrdp_surface_send_surface_bits(struct xrdp_surface* self,int bpp, char* data, +xrdp_surface_send_surface_bits(struct xrdp_surface *self, int bpp, char *data, int x, int y, int cx, int cy) { - RFX_RECT rect; - char* buf; - int Bpp; - int i; - int j; - int codecId; - uint32 bitmapDataLength; - STREAM* s; - RFX_CONTEXT* rfx_context; + RFX_RECT rect; + char *buf; + int Bpp; + int i; + int j; + int codecId; + uint32 bitmapDataLength; + STREAM *s; + RFX_CONTEXT *rfx_context; - s = (STREAM*)(self->s); - rfx_context = (RFX_CONTEXT*)(self->rfx_context); - if ((bpp == 24) || (bpp == 32)) - { - } - else - { - g_writeln("bpp = %d is not supported\n", bpp); - return 1; - } - Bpp = 4; + s = (STREAM *)(self->s); + rfx_context = (RFX_CONTEXT *)(self->rfx_context); - rect.x = 0; - rect.y = 0; - rect.width = cx; - rect.height = cy; + if ((bpp == 24) || (bpp == 32)) + { + } + else + { + g_writeln("bpp = %d is not supported\n", bpp); + return 1; + } - init_stream(self->out_s, 0); + Bpp = 4; - stream_set_pos(s, 0); - rfx_compose_message(rfx_context, s, &rect, 1, data, cx, cy, Bpp * cx); + rect.x = 0; + rect.y = 0; + rect.width = cx; + rect.height = cy; - codecId = self->session->client_info->rfx_codecId; - /* surface_bits_command */ - out_uint16_le(self->out_s, CMDTYPE_STREAM_SURFACE_BITS); /* cmdType */ - out_uint16_le(self->out_s, x); /* destLeft */ - out_uint16_le(self->out_s, y); /* destTop */ - out_uint16_le(self->out_s, x + cx); /* destRight */ - out_uint16_le(self->out_s, y + cy); /* destBottom */ - out_uint8(self->out_s, 32); /* bpp */ - out_uint8(self->out_s, 0); /* reserved1 */ - out_uint8(self->out_s, 0); /* reserved2 */ - out_uint8(self->out_s, codecId); /* codecId */ - out_uint16_le(self->out_s, cx); /* width */ - out_uint16_le(self->out_s, cy); /* height */ - bitmapDataLength = stream_get_length(s); - out_uint32_le(self->out_s, bitmapDataLength); /* bitmapDataLength */ + init_stream(self->out_s, 0); - /* rfx bit stream */ - out_uint8p(self->out_s, s->data, bitmapDataLength); + stream_set_pos(s, 0); + rfx_compose_message(rfx_context, s, &rect, 1, data, cx, cy, Bpp * cx); - s_mark_end(self->out_s); - return xrdp_fastpath_send_update_pdu(self->fastpath, - FASTPATH_UPDATETYPE_SURFCMDS, - self->out_s); + codecId = self->session->client_info->rfx_codecId; + /* surface_bits_command */ + out_uint16_le(self->out_s, CMDTYPE_STREAM_SURFACE_BITS); /* cmdType */ + out_uint16_le(self->out_s, x); /* destLeft */ + out_uint16_le(self->out_s, y); /* destTop */ + out_uint16_le(self->out_s, x + cx); /* destRight */ + out_uint16_le(self->out_s, y + cy); /* destBottom */ + out_uint8(self->out_s, 32); /* bpp */ + out_uint8(self->out_s, 0); /* reserved1 */ + out_uint8(self->out_s, 0); /* reserved2 */ + out_uint8(self->out_s, codecId); /* codecId */ + out_uint16_le(self->out_s, cx); /* width */ + out_uint16_le(self->out_s, cy); /* height */ + bitmapDataLength = stream_get_length(s); + out_uint32_le(self->out_s, bitmapDataLength); /* bitmapDataLength */ + + /* rfx bit stream */ + out_uint8p(self->out_s, s->data, bitmapDataLength); + + s_mark_end(self->out_s); + return xrdp_fastpath_send_update_pdu(self->fastpath, + FASTPATH_UPDATETYPE_SURFCMDS, + self->out_s); } /*****************************************************************************/ int APP_CC -xrdp_surface_send_frame_marker(struct xrdp_surface* self, +xrdp_surface_send_frame_marker(struct xrdp_surface *self, uint16 frameAction, uint32 frameId) { - init_stream(self->out_s, 0); - out_uint16_le(self->out_s, CMDTYPE_FRAME_MARKER); - out_uint16_le(self->out_s, frameAction); - out_uint32_le(self->out_s, frameId); - s_mark_end(self->out_s); - return xrdp_fastpath_send_update_pdu(self->fastpath, - FASTPATH_UPDATETYPE_SURFCMDS, - self->out_s); + init_stream(self->out_s, 0); + out_uint16_le(self->out_s, CMDTYPE_FRAME_MARKER); + out_uint16_le(self->out_s, frameAction); + out_uint32_le(self->out_s, frameId); + s_mark_end(self->out_s); + return xrdp_fastpath_send_update_pdu(self->fastpath, + FASTPATH_UPDATETYPE_SURFCMDS, + self->out_s); } diff --git a/libxrdp/xrdp_tcp.c b/libxrdp/xrdp_tcp.c index e4755ad6..807797a1 100644 --- a/libxrdp/xrdp_tcp.c +++ b/libxrdp/xrdp_tcp.c @@ -1,87 +1,89 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - tcp layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004 - 2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * tcp layer + */ #include "libxrdp.h" /*****************************************************************************/ -struct xrdp_tcp* APP_CC -xrdp_tcp_create(struct xrdp_iso* owner, struct trans* trans) +struct xrdp_tcp *APP_CC +xrdp_tcp_create(struct xrdp_iso *owner, struct trans *trans) { - struct xrdp_tcp* self; + struct xrdp_tcp *self; - DEBUG((" in xrdp_tcp_create")); - self = (struct xrdp_tcp*)g_malloc(sizeof(struct xrdp_tcp), 1); - self->iso_layer = owner; - self->trans = trans; - DEBUG((" out xrdp_tcp_create")); - return self; + DEBUG((" in xrdp_tcp_create")); + self = (struct xrdp_tcp *)g_malloc(sizeof(struct xrdp_tcp), 1); + self->iso_layer = owner; + self->trans = trans; + DEBUG((" out xrdp_tcp_create")); + return self; } /*****************************************************************************/ void APP_CC -xrdp_tcp_delete(struct xrdp_tcp* self) +xrdp_tcp_delete(struct xrdp_tcp *self) { - g_free(self); + g_free(self); } /*****************************************************************************/ /* get out stream ready for data */ /* returns error */ int APP_CC -xrdp_tcp_init(struct xrdp_tcp* self, struct stream* s) +xrdp_tcp_init(struct xrdp_tcp *self, struct stream *s) { - init_stream(s, 8192); - return 0; + init_stream(s, 8192); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_tcp_recv(struct xrdp_tcp* self, struct stream* s, int len) +xrdp_tcp_recv(struct xrdp_tcp *self, struct stream *s, int len) { - DEBUG((" in xrdp_tcp_recv, gota get %d bytes", len)); - init_stream(s, len); - if (trans_force_read_s(self->trans, s, len) != 0) - { - DEBUG((" error in trans_force_read_s")); - return 1; - } - DEBUG((" out xrdp_tcp_recv")); - return 0; + DEBUG((" in xrdp_tcp_recv, gota get %d bytes", len)); + init_stream(s, len); + + if (trans_force_read_s(self->trans, s, len) != 0) + { + DEBUG((" error in trans_force_read_s")); + return 1; + } + + DEBUG((" out xrdp_tcp_recv")); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_tcp_send(struct xrdp_tcp* self, struct stream* s) +xrdp_tcp_send(struct xrdp_tcp *self, struct stream *s) { - int len; - len = s->end - s->data; - DEBUG((" in xrdp_tcp_send, gota send %d bytes", len)); - if (trans_force_write_s(self->trans, s) != 0) - { - DEBUG((" error in trans_force_write_s")); - return 1; - } - DEBUG((" out xrdp_tcp_send, sent %d bytes ok", len)); - return 0; + int len; + len = s->end - s->data; + DEBUG((" in xrdp_tcp_send, gota send %d bytes", len)); + + if (trans_force_write_s(self->trans, s) != 0) + { + DEBUG((" error in trans_force_write_s")); + return 1; + } + + DEBUG((" out xrdp_tcp_send, sent %d bytes ok", len)); + return 0; } diff --git a/mc/mc.c b/mc/mc.c index 21c797d3..b585915c 100644 --- a/mc/mc.c +++ b/mc/mc.c @@ -1,114 +1,113 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2007-2010 - - media center - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * media center + */ #include "mc.h" /*****************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_start(struct mod* mod, int w, int h, int bpp) +lib_mod_start(struct mod *mod, int w, int h, int bpp) { - LIB_DEBUG(mod, "in lib_mod_start"); - mod->width = w; - mod->height = h; - mod->bpp = bpp; - LIB_DEBUG(mod, "out lib_mod_start"); - return 0; + LIB_DEBUG(mod, "in lib_mod_start"); + mod->width = w; + mod->height = h; + mod->bpp = bpp; + LIB_DEBUG(mod, "out lib_mod_start"); + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_connect(struct mod* mod) +lib_mod_connect(struct mod *mod) { - LIB_DEBUG(mod, "in lib_mod_connect"); - LIB_DEBUG(mod, "out lib_mod_connect"); - return 0; + LIB_DEBUG(mod, "in lib_mod_connect"); + LIB_DEBUG(mod, "out lib_mod_connect"); + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_event(struct mod* mod, int msg, long param1, long param2, +lib_mod_event(struct mod *mod, int msg, long param1, long param2, long param3, long param4) { - LIB_DEBUG(mod, "in lib_mod_event"); - LIB_DEBUG(mod, "out lib_mod_event"); - return 0; + LIB_DEBUG(mod, "in lib_mod_event"); + LIB_DEBUG(mod, "out lib_mod_event"); + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_signal(struct mod* mod) +lib_mod_signal(struct mod *mod) { - LIB_DEBUG(mod, "in lib_mod_signal"); - LIB_DEBUG(mod, "out lib_mod_signal"); - return 0; + LIB_DEBUG(mod, "in lib_mod_signal"); + LIB_DEBUG(mod, "out lib_mod_signal"); + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_end(struct mod* mod) +lib_mod_end(struct mod *mod) { - return 0; + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_set_param(struct mod* mod, char* name, char* value) +lib_mod_set_param(struct mod *mod, char *name, char *value) { - return 0; + return 0; } /******************************************************************************/ -struct mod* EXPORT_CC +struct mod *EXPORT_CC mod_init(void) { - struct mod* mod; + struct mod *mod; - mod = (struct mod*)g_malloc(sizeof(struct mod), 1); - mod->size = sizeof(struct mod); - mod->version = CURRENT_MOD_VER; - mod->handle = (long)mod; - mod->mod_connect = lib_mod_connect; - mod->mod_start = lib_mod_start; - mod->mod_event = lib_mod_event; - mod->mod_signal = lib_mod_signal; - mod->mod_end = lib_mod_end; - mod->mod_set_param = lib_mod_set_param; - return mod; + mod = (struct mod *)g_malloc(sizeof(struct mod), 1); + mod->size = sizeof(struct mod); + mod->version = CURRENT_MOD_VER; + mod->handle = (long)mod; + mod->mod_connect = lib_mod_connect; + mod->mod_start = lib_mod_start; + mod->mod_event = lib_mod_event; + mod->mod_signal = lib_mod_signal; + mod->mod_end = lib_mod_end; + mod->mod_set_param = lib_mod_set_param; + return mod; } /******************************************************************************/ int EXPORT_CC -mod_exit(struct mod* mod) +mod_exit(struct mod *mod) { - if (mod == 0) - { + if (mod == 0) + { + return 0; + } + + g_free(mod); return 0; - } - g_free(mod); - return 0; } diff --git a/mc/mc.h b/mc/mc.h index b1802727..1246326d 100644 --- a/mc/mc.h +++ b/mc/mc.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2007-2010 - - media center - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * media center + */ /* include other h files */ #include "arch.h" diff --git a/rdp/rdp.c b/rdp/rdp.c index 78d7cd93..f10b2760 100644 --- a/rdp/rdp.c +++ b/rdp/rdp.c @@ -1,333 +1,352 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp main file - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * librdp main file + */ #include "rdp.h" /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_start(struct mod* mod, int w, int h, int bpp) +lib_mod_start(struct mod *mod, int w, int h, int bpp) { - DEBUG(("in lib_mod_start")); - mod->width = w; - mod->height = h; - mod->rdp_bpp = bpp; - mod->xrdp_bpp = bpp; - mod->keylayout = 0x409; - g_strncpy(mod->port, "3389", 255); /* default */ - DEBUG(("out lib_mod_start")); - return 0; -} - -/******************************************************************************/ -/* return error */ -int DEFAULT_CC -lib_mod_connect(struct mod* mod) -{ - DEBUG(("in lib_mod_connect")); - /* clear screen */ - mod->server_begin_update(mod); - mod->server_set_fgcolor(mod, 0); - mod->server_fill_rect(mod, 0, 0, mod->width, mod->height); - mod->server_end_update(mod); - /* connect */ - if (rdp_rdp_connect(mod->rdp_layer, mod->ip, mod->port) == 0) - { - mod->sck = mod->rdp_layer->sec_layer->mcs_layer->iso_layer->tcp_layer->sck; - g_tcp_set_non_blocking(mod->sck); - g_tcp_set_no_delay(mod->sck); - mod->sck_obj = g_create_wait_obj_from_socket(mod->sck, 0); - DEBUG(("out lib_mod_connect")); + DEBUG(("in lib_mod_start")); + mod->width = w; + mod->height = h; + mod->rdp_bpp = bpp; + mod->xrdp_bpp = bpp; + mod->keylayout = 0x409; + g_strncpy(mod->port, "3389", 255); /* default */ + DEBUG(("out lib_mod_start")); return 0; - } - DEBUG(("out lib_mod_connect error")); - return 1; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_event(struct mod* mod, int msg, long param1, long param2, +lib_mod_connect(struct mod *mod) +{ + DEBUG(("in lib_mod_connect")); + /* clear screen */ + mod->server_begin_update(mod); + mod->server_set_fgcolor(mod, 0); + mod->server_fill_rect(mod, 0, 0, mod->width, mod->height); + mod->server_end_update(mod); + + /* connect */ + if (rdp_rdp_connect(mod->rdp_layer, mod->ip, mod->port) == 0) + { + mod->sck = mod->rdp_layer->sec_layer->mcs_layer->iso_layer->tcp_layer->sck; + g_tcp_set_non_blocking(mod->sck); + g_tcp_set_no_delay(mod->sck); + mod->sck_obj = g_create_wait_obj_from_socket(mod->sck, 0); + DEBUG(("out lib_mod_connect")); + return 0; + } + + DEBUG(("out lib_mod_connect error")); + return 1; +} + +/******************************************************************************/ +/* return error */ +int DEFAULT_CC +lib_mod_event(struct mod *mod, int msg, long param1, long param2, long param3, long param4) { - struct stream* s; + struct stream *s; - if (!mod->up_and_running) - { + if (!mod->up_and_running) + { + return 0; + } + + DEBUG(("in lib_mod_event")); + make_stream(s); + init_stream(s, 8192 * 2); + + switch (msg) + { + case 15: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SCANCODE, + param4, param3, 0); + break; + case 16: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SCANCODE, + param4, param3, 0); + break; + case 17: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SYNCHRONIZE, + param4, param3, 0); + break; + case 100: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_MOVE, param1, param2); + break; + case 101: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON1, param1, param2); + break; + case 102: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON1 | MOUSE_FLAG_DOWN, + param1, param2); + break; + case 103: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON2, param1, param2); + break; + case 104: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON2 | MOUSE_FLAG_DOWN, + param1, param2); + break; + case 105: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON3, param1, param2); + break; + case 106: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON3 | MOUSE_FLAG_DOWN, + param1, param2); + break; + case 107: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON4, param1, param2); + break; + case 108: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON4 | MOUSE_FLAG_DOWN, + param1, param2); + break; + case 109: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON5, param1, param2); + break; + case 110: + rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, + MOUSE_FLAG_BUTTON5 | MOUSE_FLAG_DOWN, + param1, param2); + break; + case 200: + rdp_rdp_send_invalidate(mod->rdp_layer, s, + (param1 >> 16) & 0xffff, param1 & 0xffff, + (param2 >> 16) & 0xffff, param2 & 0xffff); + break; + } + + free_stream(s); + DEBUG(("out lib_mod_event")); return 0; - } - DEBUG(("in lib_mod_event")); - make_stream(s); - init_stream(s, 8192 * 2); - switch (msg) - { - case 15: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SCANCODE, - param4, param3, 0); - break; - case 16: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SCANCODE, - param4, param3, 0); - break; - case 17: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_SYNCHRONIZE, - param4, param3, 0); - break; - case 100: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_MOVE, param1, param2); - break; - case 101: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON1, param1, param2); - break; - case 102: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON1 | MOUSE_FLAG_DOWN, - param1, param2); - break; - case 103: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON2, param1, param2); - break; - case 104: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON2 | MOUSE_FLAG_DOWN, - param1, param2); - break; - case 105: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON3, param1, param2); - break; - case 106: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON3 | MOUSE_FLAG_DOWN, - param1, param2); - break; - case 107: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON4, param1, param2); - break; - case 108: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON4 | MOUSE_FLAG_DOWN, - param1, param2); - break; - case 109: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON5, param1, param2); - break; - case 110: - rdp_rdp_send_input(mod->rdp_layer, s, 0, RDP_INPUT_MOUSE, - MOUSE_FLAG_BUTTON5 | MOUSE_FLAG_DOWN, - param1, param2); - break; - case 200: - rdp_rdp_send_invalidate(mod->rdp_layer, s, - (param1 >> 16) & 0xffff, param1 & 0xffff, - (param2 >> 16) & 0xffff, param2 & 0xffff); - break; - } - free_stream(s); - DEBUG(("out lib_mod_event")); - return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_signal(struct mod* mod) +lib_mod_signal(struct mod *mod) { - int type; - int cont; - struct stream* s; + int type; + int cont; + struct stream *s; - DEBUG(("in lib_mod_signal")); - if (mod->in_s == 0) - { - make_stream(mod->in_s); - } - s = mod->in_s; - init_stream(s, 8192 * 2); - cont = 1; - while (cont) - { - type = 0; - if (rdp_rdp_recv(mod->rdp_layer, s, &type) != 0) + DEBUG(("in lib_mod_signal")); + + if (mod->in_s == 0) { - DEBUG(("out lib_mod_signal error rdp_rdp_recv failed")); - return 1; + make_stream(mod->in_s); } - DEBUG(("lib_mod_signal type %d", type)); - switch (type) + + s = mod->in_s; + init_stream(s, 8192 * 2); + cont = 1; + + while (cont) { - case RDP_PDU_DATA: - rdp_rdp_process_data_pdu(mod->rdp_layer, s); - break; - case RDP_PDU_DEMAND_ACTIVE: - rdp_rdp_process_demand_active(mod->rdp_layer, s); - mod->up_and_running = 1; - break; - case RDP_PDU_DEACTIVATE: - mod->up_and_running = 0; - break; - case RDP_PDU_REDIRECT: - break; - case 0: - break; - default: - break; + type = 0; + + if (rdp_rdp_recv(mod->rdp_layer, s, &type) != 0) + { + DEBUG(("out lib_mod_signal error rdp_rdp_recv failed")); + return 1; + } + + DEBUG(("lib_mod_signal type %d", type)); + + switch (type) + { + case RDP_PDU_DATA: + rdp_rdp_process_data_pdu(mod->rdp_layer, s); + break; + case RDP_PDU_DEMAND_ACTIVE: + rdp_rdp_process_demand_active(mod->rdp_layer, s); + mod->up_and_running = 1; + break; + case RDP_PDU_DEACTIVATE: + mod->up_and_running = 0; + break; + case RDP_PDU_REDIRECT: + break; + case 0: + break; + default: + break; + } + + cont = s->next_packet < s->end; } - cont = s->next_packet < s->end; - } - DEBUG(("out lib_mod_signal")); - return 0; + + DEBUG(("out lib_mod_signal")); + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_end(struct mod* mod) +lib_mod_end(struct mod *mod) { - rdp_rdp_delete(mod->rdp_layer); - mod->rdp_layer = 0; - free_stream(mod->in_s); - mod->in_s = 0; - if (mod->sck_obj != 0) - { - g_delete_wait_obj_from_socket(mod->sck_obj); - mod->sck_obj = 0; - } - if (mod->sck != 0) - { - g_tcp_close(mod->sck); - mod->sck = 0; - } - return 0; -} + rdp_rdp_delete(mod->rdp_layer); + mod->rdp_layer = 0; + free_stream(mod->in_s); + mod->in_s = 0; -/******************************************************************************/ -/* return error */ -int DEFAULT_CC -lib_mod_set_param(struct mod* mod, char* name, char* value) -{ - if (g_strncasecmp(name, "ip", 255) == 0) - { - g_strncpy(mod->ip, value, 255); - } - else if (g_strncasecmp(name, "port", 255) == 0) - { - g_strncpy(mod->port, value, 255); - } - else if (g_strncasecmp(name, "username", 255) == 0) - { - g_strncpy(mod->username, value, 255); - } - else if (g_strncasecmp(name, "password", 255) == 0) - { - g_strncpy(mod->password, value, 255); - } - else if (g_strncasecmp(name, "hostname", 255) == 0) - { - g_strncpy(mod->hostname, value, 255); - } - else if (g_strncasecmp(name, "keylayout", 255) == 0) - { - mod->keylayout = g_atoi(value); - } - return 0; -} - -/******************************************************************************/ -/* return error */ -int DEFAULT_CC -lib_mod_get_wait_objs(struct mod* mod, tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout) -{ - int i; - - i = *rcount; - if (mod != 0) - { if (mod->sck_obj != 0) { - read_objs[i++] = mod->sck_obj; + g_delete_wait_obj_from_socket(mod->sck_obj); + mod->sck_obj = 0; } - } - *rcount = i; - return 0; + + if (mod->sck != 0) + { + g_tcp_close(mod->sck); + mod->sck = 0; + } + + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_check_wait_objs(struct mod* mod) +lib_mod_set_param(struct mod *mod, char *name, char *value) { - int rv; - - rv = 0; - if (mod != 0) - { - if (mod->sck_obj != 0) + if (g_strncasecmp(name, "ip", 255) == 0) { - if (g_is_wait_obj_set(mod->sck_obj)) - { - rv = lib_mod_signal(mod); - } + g_strncpy(mod->ip, value, 255); } - } - return rv; + else if (g_strncasecmp(name, "port", 255) == 0) + { + g_strncpy(mod->port, value, 255); + } + else if (g_strncasecmp(name, "username", 255) == 0) + { + g_strncpy(mod->username, value, 255); + } + else if (g_strncasecmp(name, "password", 255) == 0) + { + g_strncpy(mod->password, value, 255); + } + else if (g_strncasecmp(name, "hostname", 255) == 0) + { + g_strncpy(mod->hostname, value, 255); + } + else if (g_strncasecmp(name, "keylayout", 255) == 0) + { + mod->keylayout = g_atoi(value); + } + + return 0; } /******************************************************************************/ -struct mod* EXPORT_CC +/* return error */ +int DEFAULT_CC +lib_mod_get_wait_objs(struct mod *mod, tbus *read_objs, int *rcount, + tbus *write_objs, int *wcount, int *timeout) +{ + int i; + + i = *rcount; + + if (mod != 0) + { + if (mod->sck_obj != 0) + { + read_objs[i++] = mod->sck_obj; + } + } + + *rcount = i; + return 0; +} + +/******************************************************************************/ +/* return error */ +int DEFAULT_CC +lib_mod_check_wait_objs(struct mod *mod) +{ + int rv; + + rv = 0; + + if (mod != 0) + { + if (mod->sck_obj != 0) + { + if (g_is_wait_obj_set(mod->sck_obj)) + { + rv = lib_mod_signal(mod); + } + } + } + + return rv; +} + +/******************************************************************************/ +struct mod *EXPORT_CC mod_init(void) { - struct mod* mod; + struct mod *mod; - DEBUG(("in mod_init")); - mod = (struct mod*)g_malloc(sizeof(struct mod), 1); - mod->size = sizeof(struct mod); - mod->version = CURRENT_MOD_VER; - mod->handle = (long)mod; - mod->mod_connect = lib_mod_connect; - mod->mod_start = lib_mod_start; - mod->mod_event = lib_mod_event; - mod->mod_signal = lib_mod_signal; - mod->mod_end = lib_mod_end; - mod->mod_set_param = lib_mod_set_param; - mod->mod_get_wait_objs = lib_mod_get_wait_objs; - mod->mod_check_wait_objs = lib_mod_check_wait_objs; - mod->rdp_layer = rdp_rdp_create(mod); - DEBUG(("out mod_init")); - return mod; + DEBUG(("in mod_init")); + mod = (struct mod *)g_malloc(sizeof(struct mod), 1); + mod->size = sizeof(struct mod); + mod->version = CURRENT_MOD_VER; + mod->handle = (long)mod; + mod->mod_connect = lib_mod_connect; + mod->mod_start = lib_mod_start; + mod->mod_event = lib_mod_event; + mod->mod_signal = lib_mod_signal; + mod->mod_end = lib_mod_end; + mod->mod_set_param = lib_mod_set_param; + mod->mod_get_wait_objs = lib_mod_get_wait_objs; + mod->mod_check_wait_objs = lib_mod_check_wait_objs; + mod->rdp_layer = rdp_rdp_create(mod); + DEBUG(("out mod_init")); + return mod; } /******************************************************************************/ int EXPORT_CC -mod_exit(struct mod* mod) +mod_exit(struct mod *mod) { - DEBUG(("in mod_exit")); - g_free(mod); - DEBUG(("out mod_exit")); - return 0; + DEBUG(("in mod_exit")); + g_free(mod); + DEBUG(("out mod_exit")); + return 0; } diff --git a/rdp/rdp.h b/rdp/rdp.h index 66a72c7f..727d6c3e 100644 --- a/rdp/rdp.h +++ b/rdp/rdp.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp main header file - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * librdp main header file + */ /* include other h files */ #include "arch.h" @@ -269,7 +267,7 @@ struct mod int (*mod_get_wait_objs)(struct mod* v, tbus* read_objs, int* rcount, tbus* write_objs, int* wcount, int* timeout); int (*mod_check_wait_objs)(struct mod* v); - long mod_dumby[100 - 9]; /* align, 100 minus the number of mod + long mod_dumby[100 - 9]; /* align, 100 minus the number of mod functions above */ /* server functions */ int (*server_begin_update)(struct mod* v); diff --git a/rdp/rdp_bitmap.c b/rdp/rdp_bitmap.c index f2d31dae..adba5f6f 100644 --- a/rdp/rdp_bitmap.c +++ b/rdp/rdp_bitmap.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp bitmap routines - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * librdp bitmap routines + */ #include "rdp.h" @@ -35,891 +33,964 @@ /******************************************************************************/ #define REPEAT(statement) \ -{ \ - while ((count > 0) && (x < width)) \ - { \ - statement; \ - count--; \ - x++; \ - } \ -} + { \ + while ((count > 0) && (x < width)) \ + { \ + statement; \ + count--; \ + x++; \ + } \ + } /******************************************************************************/ #define MASK_UPDATE \ -{ \ - mixmask <<= 1; \ - if ((mixmask & 0xff) == 0) \ - { \ - mask = fom_mask ? fom_mask : CVAL(input); \ - mixmask = 1; \ - } \ -} + { \ + mixmask <<= 1; \ + if ((mixmask & 0xff) == 0) \ + { \ + mask = fom_mask ? fom_mask : CVAL(input); \ + mixmask = 1; \ + } \ + } /******************************************************************************/ /* 1 byte bitmap decompress */ /* returns boolean */ static int APP_CC -bitmap_decompress1(char* output, int width, int height, char* input, int size) +bitmap_decompress1(char *output, int width, int height, char *input, int size) { - char* prevline; - char* line; - char* end; - char color1; - char color2; - char mix; - int code; - int mixmask; - int mask; - int opcode; - int count; - int offset; - int isfillormix; - int x; - int lastopcode; - int insertmix; - int bicolor; - int fom_mask; + char *prevline; + char *line; + char *end; + char color1; + char color2; + char mix; + int code; + int mixmask; + int mask; + int opcode; + int count; + int offset; + int isfillormix; + int x; + int lastopcode; + int insertmix; + int bicolor; + int fom_mask; - end = input + size; - prevline = 0; - line = 0; - x = width; - lastopcode = -1; - insertmix = 0; - bicolor = 0; - color1 = 0; - color2 = 0; - mix = 0xff; - mask = 0; - fom_mask = 0; - - while (input < end) - { + end = input + size; + prevline = 0; + line = 0; + x = width; + lastopcode = -1; + insertmix = 0; + bicolor = 0; + color1 = 0; + color2 = 0; + mix = 0xff; + mask = 0; fom_mask = 0; - code = CVAL(input); - opcode = code >> 4; - /* Handle different opcode forms */ - switch (opcode) + + while (input < end) { - case 0xc: - case 0xd: - case 0xe: - opcode -= 6; - count = code & 0xf; - offset = 16; - break; - case 0xf: - opcode = code & 0xf; - if (opcode < 9) + fom_mask = 0; + code = CVAL(input); + opcode = code >> 4; + + /* Handle different opcode forms */ + switch (opcode) { - count = CVAL(input); - count |= CVAL(input) << 8; + 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; } - else + + /* Handle strange cases for counts */ + if (offset != 0) { - 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 == 0))) - { - insertmix = 1; - } - break; - case 8: /* Bicolor */ - color1 = CVAL(input); - case 3: /* Color */ - color2 = 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 0; - } - x = 0; - height--; - prevline = line; - line = output + height * width; - } - switch (opcode) - { - case 0: /* Fill */ - if (insertmix) - { - if (prevline == 0) + isfillormix = ((opcode == 2) || (opcode == 7)); + + if (count == 0) { - line[x] = mix; + if (isfillormix) + { + count = CVAL(input) + 1; + } + else + { + count = CVAL(input) + offset; + } } - else + else if (isfillormix) { - line[x] = prevline[x] ^ mix; + count <<= 3; } - insertmix = 0; - count--; - x++; - } - if (prevline == 0) - { - REPEAT(line[x] = 0) - } - else - { - REPEAT(line[x] = prevline[x]) - } - break; - case 1: /* Mix */ - if (prevline == 0) - { - REPEAT(line[x] = mix) - } - else - { - REPEAT(line[x] = prevline[x] ^ mix) - } - break; - case 2: /* Fill or Mix */ - if (prevline == 0) - { - 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: /* Color */ - REPEAT(line[x] = color2) - break; - case 4: /* Copy */ - REPEAT(line[x] = CVAL(input)) - break; - case 8: /* Bicolor */ - REPEAT - ( - if (bicolor) + } + + /* Read preliminary data */ + switch (opcode) + { + case 0: /* Fill */ + + if ((lastopcode == opcode) && !((x == width) && (prevline == 0))) + { + insertmix = 1; + } + + break; + case 8: /* Bicolor */ + color1 = CVAL(input); + case 3: /* Color */ + color2 = 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) { - line[x] = color2; - bicolor = 0; + if (height <= 0) + { + return 0; + } + + x = 0; + height--; + prevline = line; + line = output + height * width; } - else + + switch (opcode) { - line[x] = color1; - bicolor = 1; - count++; + case 0: /* Fill */ + + if (insertmix) + { + if (prevline == 0) + { + line[x] = mix; + } + else + { + line[x] = prevline[x] ^ mix; + } + + insertmix = 0; + count--; + x++; + } + + if (prevline == 0) + { + REPEAT(line[x] = 0) + } + else + { + REPEAT(line[x] = prevline[x]) + } + + break; + case 1: /* Mix */ + + if (prevline == 0) + { + REPEAT(line[x] = mix) + } + else + { + REPEAT(line[x] = prevline[x] ^ mix) + } + + break; + case 2: /* Fill or Mix */ + + if (prevline == 0) + { + 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: /* Color */ + REPEAT(line[x] = color2) + break; + case 4: /* Copy */ + REPEAT(line[x] = CVAL(input)) + break; + case 8: /* Bicolor */ + REPEAT + ( + + if (bicolor) + { + line[x] = color2; + bicolor = 0; + } + else + { + line[x] = color1; + bicolor = 1; + count++; + } + ) + break; + case 0xd: /* White */ + REPEAT(line[x] = 0xff) + break; + case 0xe: /* Black */ + REPEAT(line[x] = 0) + break; + default: + return 0; + break; } - ) - break; - case 0xd: /* White */ - REPEAT(line[x] = 0xff) - break; - case 0xe: /* Black */ - REPEAT(line[x] = 0) - break; - default: - return 0; - break; - } + } } - } - return 1; + + return 1; } /******************************************************************************/ /* 2 byte bitmap decompress */ /* returns boolean */ static int APP_CC -bitmap_decompress2(char* output, int width, int height, char* input, int size) +bitmap_decompress2(char *output, int width, int height, char *input, int size) { - char* prevline; - char* line; - char* end; - char color1[2]; - char color2[2]; - char mix[2]; - int code; - int mixmask; - int mask; - int opcode; - int count; - int offset; - int isfillormix; - int x; - int lastopcode; - int insertmix; - int bicolor; - int fom_mask; + char *prevline; + char *line; + char *end; + char color1[2]; + char color2[2]; + char mix[2]; + int code; + int mixmask; + int mask; + int opcode; + int count; + int offset; + int isfillormix; + int x; + int lastopcode; + int insertmix; + int bicolor; + int fom_mask; - end = input + size; - prevline = 0; - line = 0; - x = width; - lastopcode = -1; - insertmix = 0; - bicolor = 0; - color1[0] = 0; - color1[1] = 0; - color2[0] = 0; - color2[1] = 0; - mix[0] = 0xff; - mix[1] = 0xff; - mask = 0; - fom_mask = 0; - - while (input < end) - { + end = input + size; + prevline = 0; + line = 0; + x = width; + lastopcode = -1; + insertmix = 0; + bicolor = 0; + color1[0] = 0; + color1[1] = 0; + color2[0] = 0; + color2[1] = 0; + mix[0] = 0xff; + mix[1] = 0xff; + mask = 0; fom_mask = 0; - code = CVAL(input); - opcode = code >> 4; - /* Handle different opcode forms */ - switch (opcode) + + while (input < end) { - case 0xc: - case 0xd: - case 0xe: - opcode -= 6; - count = code & 0xf; - offset = 16; - break; - case 0xf: - opcode = code & 0xf; - if (opcode < 9) + fom_mask = 0; + code = CVAL(input); + opcode = code >> 4; + + /* Handle different opcode forms */ + switch (opcode) { - count = CVAL(input); - count |= CVAL(input) << 8; + 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; } - else + + /* Handle strange cases for counts */ + if (offset != 0) { - 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 == 0))) - { - insertmix = 1; - } - break; - case 8: /* Bicolor */ - color1[EIK0] = CVAL(input); - color1[EIK1] = CVAL(input); - case 3: /* Color */ - color2[EIK0] = CVAL(input); - color2[EIK1] = CVAL(input); - break; - case 6: /* SetMix/Mix */ - case 7: /* SetMix/FillOrMix */ - mix[EIK0] = CVAL(input); - mix[EIK1] = 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 0; - } - x = 0; - height--; - prevline = line; - line = output + height * (width * 2); - } - switch (opcode) - { - case 0: /* Fill */ - if (insertmix) - { - if (prevline == 0) + isfillormix = ((opcode == 2) || (opcode == 7)); + + if (count == 0) { - line[x * 2 + 0] = mix[0]; - line[x * 2 + 1] = mix[1]; + if (isfillormix) + { + count = CVAL(input) + 1; + } + else + { + count = CVAL(input) + offset; + } } - else + else if (isfillormix) { - line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; - line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; + count <<= 3; } - insertmix = 0; - count--; - x++; - } - if (prevline == 0) - { - REPEAT - ( - line[x * 2 + 0] = 0; - line[x * 2 + 1] = 0; - ) - } - else - { - REPEAT - ( - line[x * 2 + 0] = prevline[x * 2 + 0]; - line[x * 2 + 1] = prevline[x * 2 + 1]; - ) - } - break; - case 1: /* Mix */ - if (prevline == 0) - { - REPEAT - ( - line[x * 2 + 0] = mix[0]; - line[x * 2 + 1] = mix[1]; - ) - } - else - { - REPEAT - ( - line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; - line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; - ) - } - break; - case 2: /* Fill or Mix */ - if (prevline == 0) - { - REPEAT - ( - MASK_UPDATE; - if (mask & mixmask) - { - line[x * 2 + 0] = mix[0]; - line[x * 2 + 1] = mix[1]; - } - else - { - line[x * 2 + 0] = 0; - line[x * 2 + 1] = 0; - } - ) - } - else - { - REPEAT - ( - MASK_UPDATE; - if (mask & mixmask) - { - line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; - line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; - } - else - { - line[x * 2 + 0] = prevline[x * 2 + 0]; - line[x * 2 + 1] = prevline[x * 2 + 1]; - } - ) - } - break; - case 3: /* Color */ - REPEAT - ( - line[x * 2 + 0] = color2[0]; - line[x * 2 + 1] = color2[1]; - ) - break; - case 4: /* Copy */ - REPEAT - ( - line[x * 2 + EIK0] = CVAL(input); - line[x * 2 + EIK1] = CVAL(input); - ) - break; - case 8: /* Bicolor */ - REPEAT - ( - if (bicolor) + } + + /* Read preliminary data */ + switch (opcode) + { + case 0: /* Fill */ + + if ((lastopcode == opcode) && !((x == width) && (prevline == 0))) + { + insertmix = 1; + } + + break; + case 8: /* Bicolor */ + color1[EIK0] = CVAL(input); + color1[EIK1] = CVAL(input); + case 3: /* Color */ + color2[EIK0] = CVAL(input); + color2[EIK1] = CVAL(input); + break; + case 6: /* SetMix/Mix */ + case 7: /* SetMix/FillOrMix */ + mix[EIK0] = CVAL(input); + mix[EIK1] = 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) { - line[x * 2 + 0] = color2[0]; - line[x * 2 + 1] = color2[1]; - bicolor = 0; + if (height <= 0) + { + return 0; + } + + x = 0; + height--; + prevline = line; + line = output + height * (width * 2); } - else + + switch (opcode) { - line[x * 2 + 0] = color1[0]; - line[x * 2 + 1] = color1[1]; - bicolor = 1; - count++; + case 0: /* Fill */ + + if (insertmix) + { + if (prevline == 0) + { + line[x * 2 + 0] = mix[0]; + line[x * 2 + 1] = mix[1]; + } + else + { + line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; + line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; + } + + insertmix = 0; + count--; + x++; + } + + if (prevline == 0) + { + REPEAT + ( + line[x * 2 + 0] = 0; + line[x * 2 + 1] = 0; + ) + } + else + { + REPEAT + ( + line[x * 2 + 0] = prevline[x * 2 + 0]; + line[x * 2 + 1] = prevline[x * 2 + 1]; + ) + } + + break; + case 1: /* Mix */ + + if (prevline == 0) + { + REPEAT + ( + line[x * 2 + 0] = mix[0]; + line[x * 2 + 1] = mix[1]; + ) + } + else + { + REPEAT + ( + line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; + line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; + ) + } + + break; + case 2: /* Fill or Mix */ + + if (prevline == 0) + { + REPEAT + ( + MASK_UPDATE; + + if (mask & mixmask) + { + line[x * 2 + 0] = mix[0]; + line[x * 2 + 1] = mix[1]; + } + else + { + line[x * 2 + 0] = 0; + line[x * 2 + 1] = 0; + } + ) + } + else + { + REPEAT + ( + MASK_UPDATE; + + if (mask & mixmask) + { + line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0]; + line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1]; + } + else + { + line[x * 2 + 0] = prevline[x * 2 + 0]; + line[x * 2 + 1] = prevline[x * 2 + 1]; + } + ) + } + + break; + case 3: /* Color */ + REPEAT + ( + line[x * 2 + 0] = color2[0]; + line[x * 2 + 1] = color2[1]; + ) + break; + case 4: /* Copy */ + REPEAT + ( + line[x * 2 + EIK0] = CVAL(input); + line[x * 2 + EIK1] = CVAL(input); + ) + break; + case 8: /* Bicolor */ + REPEAT + ( + + if (bicolor) + { + line[x * 2 + 0] = color2[0]; + line[x * 2 + 1] = color2[1]; + bicolor = 0; + } + else + { + line[x * 2 + 0] = color1[0]; + line[x * 2 + 1] = color1[1]; + bicolor = 1; + count++; + } + ) + break; + case 0xd: /* White */ + REPEAT + ( + line[x * 2 + 0] = 0xff; + line[x * 2 + 1] = 0xff; + ) + break; + case 0xe: /* Black */ + REPEAT + ( + line[x * 2 + 0] = 0; + line[x * 2 + 1] = 0; + ) + break; + default: + return 0; + break; } - ) - break; - case 0xd: /* White */ - REPEAT - ( - line[x * 2 + 0] = 0xff; - line[x * 2 + 1] = 0xff; - ) - break; - case 0xe: /* Black */ - REPEAT - ( - line[x * 2 + 0] = 0; - line[x * 2 + 1] = 0; - ) - break; - default: - return 0; - break; - } + } } - } - return 1; + + return 1; } /******************************************************************************/ /* 3 byte bitmap decompress */ /* returns boolean */ static int APP_CC -bitmap_decompress3(char* output, int width, int height, char* input, int size) +bitmap_decompress3(char *output, int width, int height, char *input, int size) { - char* prevline; - char* line; - char* end; - char color1[3]; - char color2[3]; - char mix[3]; - int code; - int mixmask; - int mask; - int opcode; - int count; - int offset; - int isfillormix; - int x; - int lastopcode; - int insertmix; - int bicolor; - int fom_mask; + char *prevline; + char *line; + char *end; + char color1[3]; + char color2[3]; + char mix[3]; + int code; + int mixmask; + int mask; + int opcode; + int count; + int offset; + int isfillormix; + int x; + int lastopcode; + int insertmix; + int bicolor; + int fom_mask; - end = input + size; - prevline = 0; - line = 0; - x = width; - lastopcode = -1; - insertmix = 0; - bicolor = 0; - color1[0] = 0; - color1[1] = 0; - color1[2] = 0; - color2[0] = 0; - color2[1] = 0; - color2[2] = 0; - mix[0] = 0xff; - mix[1] = 0xff; - mix[2] = 0xff; - mask = 0; - fom_mask = 0; - - while (input < end) - { + end = input + size; + prevline = 0; + line = 0; + x = width; + lastopcode = -1; + insertmix = 0; + bicolor = 0; + color1[0] = 0; + color1[1] = 0; + color1[2] = 0; + color2[0] = 0; + color2[1] = 0; + color2[2] = 0; + mix[0] = 0xff; + mix[1] = 0xff; + mix[2] = 0xff; + mask = 0; fom_mask = 0; - code = CVAL(input); - opcode = code >> 4; - /* Handle different opcode forms */ - switch (opcode) + + while (input < end) { - case 0xc: - case 0xd: - case 0xe: - opcode -= 6; - count = code & 0xf; - offset = 16; - break; - case 0xf: - opcode = code & 0xf; - if (opcode < 9) + fom_mask = 0; + code = CVAL(input); + opcode = code >> 4; + + /* Handle different opcode forms */ + switch (opcode) { - count = CVAL(input); - count |= CVAL(input) << 8; + 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; } - else + + /* Handle strange cases for counts */ + if (offset != 0) { - 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 == 0))) - { - insertmix = 1; - } - break; - case 8: /* Bicolor */ - color1[0] = CVAL(input); - color1[1] = CVAL(input); - color1[2] = CVAL(input); - case 3: /* Color */ - color2[0] = CVAL(input); - color2[1] = CVAL(input); - color2[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 0; - } - x = 0; - height--; - prevline = line; - line = output + height * (width * 3); - } - switch (opcode) - { - case 0: /* Fill */ - if (insertmix) - { - if (prevline == 0) + isfillormix = ((opcode == 2) || (opcode == 7)); + + if (count == 0) { - line[x * 3 + 0] = mix[0]; - line[x * 3 + 1] = mix[1]; - line[x * 3 + 2] = mix[2]; + if (isfillormix) + { + count = CVAL(input) + 1; + } + else + { + count = CVAL(input) + offset; + } } - else + else if (isfillormix) { - line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0]; - line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1]; - line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2]; + count <<= 3; } - insertmix = 0; - count--; - x++; - } - if (prevline == 0) - { - REPEAT - ( - line[x * 3 + 0] = 0; - line[x * 3 + 1] = 0; - line[x * 3 + 2] = 0; - ) - } - else - { - REPEAT - ( - line[x * 3 + 0] = prevline[x * 3 + 0]; - line[x * 3 + 1] = prevline[x * 3 + 1]; - line[x * 3 + 2] = prevline[x * 3 + 2]; - ) - } - break; - case 1: /* Mix */ - if (prevline == 0) - { - REPEAT - ( - line[x * 3 + 0] = mix[0]; - line[x * 3 + 1] = mix[1]; - line[x * 3 + 2] = mix[2]; - ) - } - else - { - REPEAT - ( - line[x * 3 + 0] = prevline[x * 3 + 0] ^ 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 == 0) - { - REPEAT - ( - MASK_UPDATE; - if (mask & mixmask) - { - line[x * 3 + 0] = mix[0]; - line[x * 3 + 1] = mix[1]; - line[x * 3 + 2] = mix[2]; - } - else - { - line[x * 3 + 0] = 0; - line[x * 3 + 1] = 0; - line[x * 3 + 2] = 0; - } - ) - } - else - { - REPEAT - ( - MASK_UPDATE; - if (mask & mixmask) - { - line[x * 3 + 0] = prevline[x * 3 + 0] ^ 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 + 0] = prevline[x * 3 + 0]; - line[x * 3 + 1] = prevline[x * 3 + 1]; - line[x * 3 + 2] = prevline[x * 3 + 2]; - } - ) - } - break; - case 3: /* Color */ - REPEAT - ( - line[x * 3 + 0] = color2[0]; - line[x * 3 + 1] = color2[1]; - line[x * 3 + 2] = color2[2]; - ) - break; - case 4: /* Copy */ - REPEAT - ( - line[x * 3 + 0] = CVAL(input); - line[x * 3 + 1] = CVAL(input); - line[x * 3 + 2] = CVAL(input); - ) - break; - case 8: /* Bicolor */ - REPEAT - ( - if (bicolor) + } + + /* Read preliminary data */ + switch (opcode) + { + case 0: /* Fill */ + + if ((lastopcode == opcode) && !((x == width) && (prevline == 0))) + { + insertmix = 1; + } + + break; + case 8: /* Bicolor */ + color1[0] = CVAL(input); + color1[1] = CVAL(input); + color1[2] = CVAL(input); + case 3: /* Color */ + color2[0] = CVAL(input); + color2[1] = CVAL(input); + color2[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) { - line[x * 3 + 0] = color2[0]; - line[x * 3 + 1] = color2[1]; - line[x * 3 + 2] = color2[2]; - bicolor = 0; + if (height <= 0) + { + return 0; + } + + x = 0; + height--; + prevline = line; + line = output + height * (width * 3); } - else + + switch (opcode) { - line[x * 3 + 0] = color1[0]; - line[x * 3 + 1] = color1[1]; - line[x * 3 + 2] = color1[2]; - bicolor = 1; - count++; + case 0: /* Fill */ + + if (insertmix) + { + if (prevline == 0) + { + line[x * 3 + 0] = mix[0]; + line[x * 3 + 1] = mix[1]; + line[x * 3 + 2] = mix[2]; + } + else + { + line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0]; + line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1]; + line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2]; + } + + insertmix = 0; + count--; + x++; + } + + if (prevline == 0) + { + REPEAT + ( + line[x * 3 + 0] = 0; + line[x * 3 + 1] = 0; + line[x * 3 + 2] = 0; + ) + } + else + { + REPEAT + ( + line[x * 3 + 0] = prevline[x * 3 + 0]; + line[x * 3 + 1] = prevline[x * 3 + 1]; + line[x * 3 + 2] = prevline[x * 3 + 2]; + ) + } + + break; + case 1: /* Mix */ + + if (prevline == 0) + { + REPEAT + ( + line[x * 3 + 0] = mix[0]; + line[x * 3 + 1] = mix[1]; + line[x * 3 + 2] = mix[2]; + ) + } + else + { + REPEAT + ( + line[x * 3 + 0] = prevline[x * 3 + 0] ^ 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 == 0) + { + REPEAT + ( + MASK_UPDATE; + + if (mask & mixmask) + { + line[x * 3 + 0] = mix[0]; + line[x * 3 + 1] = mix[1]; + line[x * 3 + 2] = mix[2]; + } + else + { + line[x * 3 + 0] = 0; + line[x * 3 + 1] = 0; + line[x * 3 + 2] = 0; + } + ) + } + else + { + REPEAT + ( + MASK_UPDATE; + + if (mask & mixmask) + { + line[x * 3 + 0] = prevline[x * 3 + 0] ^ 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 + 0] = prevline[x * 3 + 0]; + line[x * 3 + 1] = prevline[x * 3 + 1]; + line[x * 3 + 2] = prevline[x * 3 + 2]; + } + ) + } + + break; + case 3: /* Color */ + REPEAT + ( + line[x * 3 + 0] = color2[0]; + line[x * 3 + 1] = color2[1]; + line[x * 3 + 2] = color2[2]; + ) + break; + case 4: /* Copy */ + REPEAT + ( + line[x * 3 + 0] = CVAL(input); + line[x * 3 + 1] = CVAL(input); + line[x * 3 + 2] = CVAL(input); + ) + break; + case 8: /* Bicolor */ + REPEAT + ( + + if (bicolor) + { + line[x * 3 + 0] = color2[0]; + line[x * 3 + 1] = color2[1]; + line[x * 3 + 2] = color2[2]; + bicolor = 0; + } + else + { + line[x * 3 + 0] = color1[0]; + line[x * 3 + 1] = color1[1]; + line[x * 3 + 2] = color1[2]; + bicolor = 1; + count++; + } + ) + break; + case 0xd: /* White */ + REPEAT + ( + line[x * 3 + 0] = 0xff; + line[x * 3 + 1] = 0xff; + line[x * 3 + 2] = 0xff; + ) + break; + case 0xe: /* Black */ + REPEAT + ( + line[x * 3 + 0] = 0; + line[x * 3 + 1] = 0; + line[x * 3 + 2] = 0; + ) + break; + default: + return 0; + break; } - ) - break; - case 0xd: /* White */ - REPEAT - ( - line[x * 3 + 0] = 0xff; - line[x * 3 + 1] = 0xff; - line[x * 3 + 2] = 0xff; - ) - break; - case 0xe: /* Black */ - REPEAT - ( - line[x * 3 + 0] = 0; - line[x * 3 + 1] = 0; - line[x * 3 + 2] = 0; - ) - break; - default: - return 0; - break; - } + } } - } - return 1; + + return 1; } /*****************************************************************************/ /* returns boolean */ int APP_CC -rdp_bitmap_decompress(char* output, int width, int height, char* input, +rdp_bitmap_decompress(char *output, int width, int height, char *input, int size, int Bpp) { - int rv; + int rv; - 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; - default: - rv = 0; - break; - } - return rv; + 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; + default: + rv = 0; + break; + } + + return rv; } diff --git a/rdp/rdp_iso.c b/rdp/rdp_iso.c index 3db99dd4..09c874b6 100644 --- a/rdp/rdp_iso.c +++ b/rdp/rdp_iso.c @@ -1,219 +1,239 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp iso layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * librdp iso layer + */ #include "rdp.h" /*****************************************************************************/ -struct rdp_iso* APP_CC -rdp_iso_create(struct rdp_mcs* owner) +struct rdp_iso *APP_CC +rdp_iso_create(struct rdp_mcs *owner) { - struct rdp_iso* self; + struct rdp_iso *self; - self = (struct rdp_iso*)g_malloc(sizeof(struct rdp_iso), 1); - self->mcs_layer = owner; - self->tcp_layer = rdp_tcp_create(self); - return self; + self = (struct rdp_iso *)g_malloc(sizeof(struct rdp_iso), 1); + self->mcs_layer = owner; + self->tcp_layer = rdp_tcp_create(self); + return self; } /*****************************************************************************/ void APP_CC -rdp_iso_delete(struct rdp_iso* self) +rdp_iso_delete(struct rdp_iso *self) { - if (self == 0) - { - return; - } - rdp_tcp_delete(self->tcp_layer); - g_free(self); + if (self == 0) + { + return; + } + + rdp_tcp_delete(self->tcp_layer); + g_free(self); } /*****************************************************************************/ /* returns error */ static int APP_CC -rdp_iso_recv_msg(struct rdp_iso* self, struct stream* s, int* code) +rdp_iso_recv_msg(struct rdp_iso *self, struct stream *s, int *code) { - int ver; - int len; + int ver; + int len; + + *code = 0; + + if (rdp_tcp_recv(self->tcp_layer, s, 4) != 0) + { + DEBUG((" out rdp_iso_recv_msg error rdp_tcp_recv 1 failed")); + return 1; + } + + in_uint8(s, ver); + + if (ver != 3) + { + DEBUG((" out rdp_iso_recv_msg error ver != 3")); + return 1; + } - *code = 0; - if (rdp_tcp_recv(self->tcp_layer, s, 4) != 0) - { - DEBUG((" out rdp_iso_recv_msg error rdp_tcp_recv 1 failed")); - return 1; - } - in_uint8(s, ver); - if (ver != 3) - { - DEBUG((" out rdp_iso_recv_msg error ver != 3")); - return 1; - } - in_uint8s(s, 1); - in_uint16_be(s, len); - if (rdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) - { - DEBUG((" out rdp_iso_recv_msg error rdp_tcp_recv 2 failed")); - return 1; - } - in_uint8s(s, 1); - in_uint8(s, *code); - if (*code == ISO_PDU_DT) - { in_uint8s(s, 1); - } - else - { - in_uint8s(s, 5); - } - return 0; + in_uint16_be(s, len); + + if (rdp_tcp_recv(self->tcp_layer, s, len - 4) != 0) + { + DEBUG((" out rdp_iso_recv_msg error rdp_tcp_recv 2 failed")); + return 1; + } + + in_uint8s(s, 1); + in_uint8(s, *code); + + if (*code == ISO_PDU_DT) + { + in_uint8s(s, 1); + } + else + { + in_uint8s(s, 5); + } + + return 0; } /*****************************************************************************/ static int APP_CC -rdp_iso_send_msg(struct rdp_iso* self, struct stream* s, int code) +rdp_iso_send_msg(struct rdp_iso *self, struct stream *s, int code) { - if (rdp_tcp_init(self->tcp_layer, s) != 0) - { - return 1; - } - out_uint8(s, 3); - out_uint8(s, 0); - out_uint16_be(s, 11); /* length */ - out_uint8(s, 6); - out_uint8(s, code); - out_uint16_le(s, 0); - out_uint16_le(s, 0); - out_uint8(s, 0); - s_mark_end(s); - if (rdp_tcp_send(self->tcp_layer, s) != 0) - { - return 1; - } - return 0; + if (rdp_tcp_init(self->tcp_layer, s) != 0) + { + return 1; + } + + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, 11); /* length */ + out_uint8(s, 6); + out_uint8(s, code); + out_uint16_le(s, 0); + out_uint16_le(s, 0); + out_uint8(s, 0); + s_mark_end(s); + + if (rdp_tcp_send(self->tcp_layer, s) != 0) + { + return 1; + } + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_iso_recv(struct rdp_iso* self, struct stream* s) +rdp_iso_recv(struct rdp_iso *self, struct stream *s) { - int code; + int code; - if (rdp_iso_recv_msg(self, s, &code) != 0) - { - return 1; - } - if (code != ISO_PDU_DT) - { - return 1; - } - return 0; + if (rdp_iso_recv_msg(self, s, &code) != 0) + { + return 1; + } + + if (code != ISO_PDU_DT) + { + return 1; + } + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_iso_init(struct rdp_iso* self, struct stream* s) +rdp_iso_init(struct rdp_iso *self, struct stream *s) { - rdp_tcp_init(self->tcp_layer, s); - s_push_layer(s, iso_hdr, 7); - return 0; + rdp_tcp_init(self->tcp_layer, s); + s_push_layer(s, iso_hdr, 7); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_iso_send(struct rdp_iso* self, struct stream* s) +rdp_iso_send(struct rdp_iso *self, struct stream *s) { - int len; + int len; - s_pop_layer(s, iso_hdr); - len = s->end - s->p; - out_uint8(s, 3); - out_uint8(s, 0); - out_uint16_be(s, len); - out_uint8(s, 2); - out_uint8(s, ISO_PDU_DT); - out_uint8(s, 0x80); - if (rdp_tcp_send(self->tcp_layer, s) != 0) - { - return 1; - } - return 0; + s_pop_layer(s, iso_hdr); + len = s->end - s->p; + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, len); + out_uint8(s, 2); + out_uint8(s, ISO_PDU_DT); + out_uint8(s, 0x80); + + if (rdp_tcp_send(self->tcp_layer, s) != 0) + { + return 1; + } + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_iso_connect(struct rdp_iso* self, char* ip, char* port) +rdp_iso_connect(struct rdp_iso *self, char *ip, char *port) { - int code; - struct stream* s; + int code; + struct stream *s; + + DEBUG((" in rdp_iso_connect")); + make_stream(s); + init_stream(s, 8192); + + if (rdp_tcp_connect(self->tcp_layer, ip, port) != 0) + { + free_stream(s); + DEBUG((" out rdp_iso_connect error rdp_tcp_connect failed")); + return 1; + } + + if (rdp_iso_send_msg(self, s, ISO_PDU_CR) != 0) + { + free_stream(s); + rdp_tcp_disconnect(self->tcp_layer); + DEBUG((" out rdp_iso_connect error rdp_iso_send_msg failed")); + return 1; + } + + init_stream(s, 8192); + + if (rdp_iso_recv_msg(self, s, &code) != 0) + { + free_stream(s); + rdp_tcp_disconnect(self->tcp_layer); + DEBUG((" out rdp_iso_connect error rdp_iso_recv_msg failed")); + return 1; + } + + if (code != ISO_PDU_CC) + { + free_stream(s); + rdp_tcp_disconnect(self->tcp_layer); + DEBUG((" out rdp_iso_connect error code != ISO_PDU_CC")); + return 1; + } - DEBUG((" in rdp_iso_connect")); - make_stream(s); - init_stream(s, 8192); - if (rdp_tcp_connect(self->tcp_layer, ip, port) != 0) - { - free_stream(s); - DEBUG((" out rdp_iso_connect error rdp_tcp_connect failed")); - return 1; - } - if (rdp_iso_send_msg(self, s, ISO_PDU_CR) != 0) - { free_stream(s); + DEBUG((" out rdp_iso_connect")); + return 0; +} + +/*****************************************************************************/ +int APP_CC +rdp_iso_disconnect(struct rdp_iso *self) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + rdp_iso_send_msg(self, s, ISO_PDU_DR); rdp_tcp_disconnect(self->tcp_layer); - DEBUG((" out rdp_iso_connect error rdp_iso_send_msg failed")); - return 1; - } - init_stream(s, 8192); - if (rdp_iso_recv_msg(self, s, &code) != 0) - { free_stream(s); - rdp_tcp_disconnect(self->tcp_layer); - DEBUG((" out rdp_iso_connect error rdp_iso_recv_msg failed")); - return 1; - } - if (code != ISO_PDU_CC) - { - free_stream(s); - rdp_tcp_disconnect(self->tcp_layer); - DEBUG((" out rdp_iso_connect error code != ISO_PDU_CC")); - return 1; - } - free_stream(s); - DEBUG((" out rdp_iso_connect")); - return 0; -} - -/*****************************************************************************/ -int APP_CC -rdp_iso_disconnect(struct rdp_iso* self) -{ - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - rdp_iso_send_msg(self, s, ISO_PDU_DR); - rdp_tcp_disconnect(self->tcp_layer); - free_stream(s); - return 0; + return 0; } diff --git a/rdp/rdp_lic.c b/rdp/rdp_lic.c index a729a7bc..ce9a0624 100644 --- a/rdp/rdp_lic.c +++ b/rdp/rdp_lic.c @@ -1,358 +1,369 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - licence - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * licence + */ #include "rdp.h" /*****************************************************************************/ -struct rdp_lic* APP_CC -rdp_lic_create(struct rdp_sec* owner) +struct rdp_lic *APP_CC +rdp_lic_create(struct rdp_sec *owner) { - struct rdp_lic* self; + struct rdp_lic *self; - self = (struct rdp_lic*)g_malloc(sizeof(struct rdp_lic), 1); - self->sec_layer = owner; - return self; + self = (struct rdp_lic *)g_malloc(sizeof(struct rdp_lic), 1); + self->sec_layer = owner; + return self; } /*****************************************************************************/ void APP_CC -rdp_lic_delete(struct rdp_lic* self) +rdp_lic_delete(struct rdp_lic *self) { - if (self == 0) - { - return; - } - g_free(self); + if (self == 0) + { + return; + } + + g_free(self); } /*****************************************************************************/ /* Generate a session key and RC4 keys, given client and server randoms */ static void APP_CC -rdp_lic_generate_keys(struct rdp_lic* self, char* client_random, - char* server_random, char* pre_master_secret) +rdp_lic_generate_keys(struct rdp_lic *self, char *client_random, + char *server_random, char *pre_master_secret) { - char master_secret[48]; - char key_block[48]; + char master_secret[48]; + char key_block[48]; - /* Generate master secret and then key material */ - rdp_sec_hash_48(master_secret, pre_master_secret, client_random, - server_random, 65); - rdp_sec_hash_48(key_block, master_secret, server_random, - client_random, 65); - /* Store first 16 bytes of session key as MAC secret */ - g_memcpy(self->licence_sign_key, key_block, 16); - /* Generate RC4 key from next 16 bytes */ - rdp_sec_hash_16(self->licence_key, key_block + 16, client_random, - server_random); + /* Generate master secret and then key material */ + rdp_sec_hash_48(master_secret, pre_master_secret, client_random, + server_random, 65); + rdp_sec_hash_48(key_block, master_secret, server_random, + client_random, 65); + /* Store first 16 bytes of session key as MAC secret */ + g_memcpy(self->licence_sign_key, key_block, 16); + /* Generate RC4 key from next 16 bytes */ + rdp_sec_hash_16(self->licence_key, key_block + 16, client_random, + server_random); } /*****************************************************************************/ static void APP_CC -rdp_lic_generate_hwid(struct rdp_lic* self, char* hwid) +rdp_lic_generate_hwid(struct rdp_lic *self, char *hwid) { - rdp_sec_buf_out_uint32(hwid, 2); - g_strncpy(hwid + 4, self->sec_layer->rdp_layer->mod->hostname, - LICENCE_HWID_SIZE - 4); + rdp_sec_buf_out_uint32(hwid, 2); + g_strncpy(hwid + 4, self->sec_layer->rdp_layer->mod->hostname, + LICENCE_HWID_SIZE - 4); } /*****************************************************************************/ /* Present an existing licence to the server */ static void APP_CC -rdp_lic_present(struct rdp_lic* self, char* client_random, char* rsa_data, - char* licence_data, int licence_size, char* hwid, - char* signature) +rdp_lic_present(struct rdp_lic *self, char *client_random, char *rsa_data, + char *licence_data, int licence_size, char *hwid, + char *signature) { - int sec_flags; - int length; - struct stream* s; + int sec_flags; + int length; + struct stream *s; - sec_flags = SEC_LICENCE_NEG; - length = 16 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + - licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE; - make_stream(s); - init_stream(s, 8192); - rdp_sec_init(self->sec_layer, s, sec_flags); - out_uint8(s, LICENCE_TAG_PRESENT); - out_uint8(s, 2); /* version */ - out_uint16_le(s, length); - out_uint32_le(s, 1); - out_uint16_le(s, 0); - out_uint16_le(s, 0x0201); - out_uint8p(s, client_random, SEC_RANDOM_SIZE); - out_uint16_le(s, 0); - 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); - rdp_sec_send(self->sec_layer, s, sec_flags); - free_stream(s); + sec_flags = SEC_LICENCE_NEG; + length = 16 + SEC_RANDOM_SIZE + SEC_MODULUS_SIZE + SEC_PADDING_SIZE + + licence_size + LICENCE_HWID_SIZE + LICENCE_SIGNATURE_SIZE; + make_stream(s); + init_stream(s, 8192); + rdp_sec_init(self->sec_layer, s, sec_flags); + out_uint8(s, LICENCE_TAG_PRESENT); + out_uint8(s, 2); /* version */ + out_uint16_le(s, length); + out_uint32_le(s, 1); + out_uint16_le(s, 0); + out_uint16_le(s, 0x0201); + out_uint8p(s, client_random, SEC_RANDOM_SIZE); + out_uint16_le(s, 0); + 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); + rdp_sec_send(self->sec_layer, s, sec_flags); + free_stream(s); } /*****************************************************************************/ /* Send a licence request packet */ static void APP_CC -rdp_lic_send_request(struct rdp_lic* self, char* client_random, - char* rsa_data, char* user, char* host) +rdp_lic_send_request(struct rdp_lic *self, char *client_random, + char *rsa_data, char *user, char *host) { - int sec_flags; - int userlen; - int hostlen; - int length; - struct stream* s; + int sec_flags; + int userlen; + int hostlen; + int length; + struct stream *s; - sec_flags = SEC_LICENCE_NEG; - userlen = g_strlen(user) + 1; - hostlen = g_strlen(host) + 1; - length = 128 + userlen + hostlen; - make_stream(s); - init_stream(s, 8192); - rdp_sec_init(self->sec_layer, s, sec_flags); - out_uint8(s, LICENCE_TAG_REQUEST); - out_uint8(s, 2); /* version */ - out_uint16_le(s, length); - out_uint32_le(s, 1); - out_uint16_le(s, 0); - out_uint16_le(s, 0xff01); - out_uint8p(s, client_random, SEC_RANDOM_SIZE); - out_uint16_le(s, 0); - 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, LICENCE_TAG_USER); - out_uint16_le(s, userlen); - out_uint8p(s, user, userlen); - out_uint16_le(s, LICENCE_TAG_HOST); - out_uint16_le(s, hostlen); - out_uint8p(s, host, hostlen); - s_mark_end(s); - rdp_sec_send(self->sec_layer, s, sec_flags); - free_stream(s); + sec_flags = SEC_LICENCE_NEG; + userlen = g_strlen(user) + 1; + hostlen = g_strlen(host) + 1; + length = 128 + userlen + hostlen; + make_stream(s); + init_stream(s, 8192); + rdp_sec_init(self->sec_layer, s, sec_flags); + out_uint8(s, LICENCE_TAG_REQUEST); + out_uint8(s, 2); /* version */ + out_uint16_le(s, length); + out_uint32_le(s, 1); + out_uint16_le(s, 0); + out_uint16_le(s, 0xff01); + out_uint8p(s, client_random, SEC_RANDOM_SIZE); + out_uint16_le(s, 0); + 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, LICENCE_TAG_USER); + out_uint16_le(s, userlen); + out_uint8p(s, user, userlen); + out_uint16_le(s, LICENCE_TAG_HOST); + out_uint16_le(s, hostlen); + out_uint8p(s, host, hostlen); + s_mark_end(s); + rdp_sec_send(self->sec_layer, s, sec_flags); + free_stream(s); } /*****************************************************************************/ /* Process a licence demand packet */ static void APP_CC -rdp_lic_process_demand(struct rdp_lic* self, struct stream* s) +rdp_lic_process_demand(struct rdp_lic *self, struct stream *s) { - char null_data[SEC_MODULUS_SIZE]; - char* server_random; - char signature[LICENCE_SIGNATURE_SIZE]; - char hwid[LICENCE_HWID_SIZE]; - char* licence_data; - int licence_size; - void* crypt_key; + char null_data[SEC_MODULUS_SIZE]; + char *server_random; + char signature[LICENCE_SIGNATURE_SIZE]; + char hwid[LICENCE_HWID_SIZE]; + char *licence_data; + int licence_size; + void *crypt_key; - licence_data = 0; - /* 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. */ - g_memset(null_data, 0, sizeof(null_data)); - rdp_lic_generate_keys(self, null_data, server_random, null_data); - licence_size = 0; /* todo load_licence(&licence_data); */ - if (licence_size > 0) - { - /* Generate a signature for the HWID buffer */ - rdp_lic_generate_hwid(self, hwid); - rdp_sec_sign(signature, 16, self->licence_sign_key, 16, - hwid, sizeof(hwid)); - /* Now encrypt the HWID */ - crypt_key = ssl_rc4_info_create(); - ssl_rc4_set_key(crypt_key, self->licence_key, 16); - ssl_rc4_crypt(crypt_key, hwid, sizeof(hwid)); - ssl_rc4_info_delete(crypt_key); - rdp_lic_present(self, null_data, null_data, licence_data, - licence_size, hwid, signature); - g_free(licence_data); - return; - } - rdp_lic_send_request(self, null_data, null_data, - self->sec_layer->rdp_layer->mod->username, - self->sec_layer->rdp_layer->mod->hostname); + licence_data = 0; + /* 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. */ + g_memset(null_data, 0, sizeof(null_data)); + rdp_lic_generate_keys(self, null_data, server_random, null_data); + licence_size = 0; /* todo load_licence(&licence_data); */ + + if (licence_size > 0) + { + /* Generate a signature for the HWID buffer */ + rdp_lic_generate_hwid(self, hwid); + rdp_sec_sign(signature, 16, self->licence_sign_key, 16, + hwid, sizeof(hwid)); + /* Now encrypt the HWID */ + crypt_key = ssl_rc4_info_create(); + ssl_rc4_set_key(crypt_key, self->licence_key, 16); + ssl_rc4_crypt(crypt_key, hwid, sizeof(hwid)); + ssl_rc4_info_delete(crypt_key); + rdp_lic_present(self, null_data, null_data, licence_data, + licence_size, hwid, signature); + g_free(licence_data); + return; + } + + rdp_lic_send_request(self, null_data, null_data, + self->sec_layer->rdp_layer->mod->username, + self->sec_layer->rdp_layer->mod->hostname); } /*****************************************************************************/ /* Send an authentication response packet */ static void APP_CC -rdp_lic_send_authresp(struct rdp_lic* self, char* token, char* crypt_hwid, - char* signature) +rdp_lic_send_authresp(struct rdp_lic *self, char *token, char *crypt_hwid, + char *signature) { - int sec_flags; - int length; - struct stream* s; + int sec_flags; + int length; + struct stream *s; - sec_flags = SEC_LICENCE_NEG; - length = 58; - make_stream(s); - init_stream(s, 8192); - rdp_sec_init(self->sec_layer, s, sec_flags); - out_uint8(s, LICENCE_TAG_AUTHRESP); - out_uint8(s, 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); - rdp_sec_send(self->sec_layer, s, sec_flags); - free_stream(s); + sec_flags = SEC_LICENCE_NEG; + length = 58; + make_stream(s); + init_stream(s, 8192); + rdp_sec_init(self->sec_layer, s, sec_flags); + out_uint8(s, LICENCE_TAG_AUTHRESP); + out_uint8(s, 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); + rdp_sec_send(self->sec_layer, s, sec_flags); + free_stream(s); } /*****************************************************************************/ /* Parse an authentication request packet */ /* returns boolean */ static int APP_CC -rdp_lic_parse_authreq(struct rdp_lic* self, struct stream* s, - char** token, char** signature) +rdp_lic_parse_authreq(struct rdp_lic *self, struct stream *s, + char **token, char **signature) { - int tokenlen; + int 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 0; - } - in_uint8p(s, *token, tokenlen); - in_uint8p(s, *signature, LICENCE_SIGNATURE_SIZE); - return s_check_end(s); + 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 0; + } + + in_uint8p(s, *token, tokenlen); + in_uint8p(s, *signature, LICENCE_SIGNATURE_SIZE); + return s_check_end(s); } /*****************************************************************************/ /* Process an authentication request packet */ static void APP_CC -rdp_lic_process_authreq(struct rdp_lic* self, struct stream* s) +rdp_lic_process_authreq(struct rdp_lic *self, struct stream *s) { - char* in_token; - char* in_sig; - char out_token[LICENCE_TOKEN_SIZE]; - char decrypt_token[LICENCE_TOKEN_SIZE]; - char hwid[LICENCE_HWID_SIZE]; - char crypt_hwid[LICENCE_HWID_SIZE]; - char sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE]; - char out_sig[LICENCE_SIGNATURE_SIZE]; - void* crypt_key; + char *in_token; + char *in_sig; + char out_token[LICENCE_TOKEN_SIZE]; + char decrypt_token[LICENCE_TOKEN_SIZE]; + char hwid[LICENCE_HWID_SIZE]; + char crypt_hwid[LICENCE_HWID_SIZE]; + char sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE]; + char out_sig[LICENCE_SIGNATURE_SIZE]; + void *crypt_key; - in_token = 0; - in_sig = 0; - /* Parse incoming packet and save the encrypted token */ - rdp_lic_parse_authreq(self, s, &in_token, &in_sig); - g_memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); - /* Decrypt the token. It should read TEST in Unicode. */ - crypt_key = ssl_rc4_info_create(); - ssl_rc4_set_key(crypt_key, self->licence_key, 16); - g_memcpy(decrypt_token, in_token, LICENCE_TOKEN_SIZE); - ssl_rc4_crypt(crypt_key, decrypt_token, LICENCE_TOKEN_SIZE); - /* Generate a signature for a buffer of token and HWID */ - rdp_lic_generate_hwid(self, hwid); - g_memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE); - g_memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE); - rdp_sec_sign(out_sig, 16, self->licence_sign_key, 16, sealed_buffer, - sizeof(sealed_buffer)); - /* Now encrypt the HWID */ - ssl_rc4_set_key(crypt_key, self->licence_key, 16); - g_memcpy(crypt_hwid, hwid, LICENCE_HWID_SIZE); - ssl_rc4_crypt(crypt_key, crypt_hwid, LICENCE_HWID_SIZE); - rdp_lic_send_authresp(self, out_token, crypt_hwid, out_sig); - ssl_rc4_info_delete(crypt_key); + in_token = 0; + in_sig = 0; + /* Parse incoming packet and save the encrypted token */ + rdp_lic_parse_authreq(self, s, &in_token, &in_sig); + g_memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); + /* Decrypt the token. It should read TEST in Unicode. */ + crypt_key = ssl_rc4_info_create(); + ssl_rc4_set_key(crypt_key, self->licence_key, 16); + g_memcpy(decrypt_token, in_token, LICENCE_TOKEN_SIZE); + ssl_rc4_crypt(crypt_key, decrypt_token, LICENCE_TOKEN_SIZE); + /* Generate a signature for a buffer of token and HWID */ + rdp_lic_generate_hwid(self, hwid); + g_memcpy(sealed_buffer, decrypt_token, LICENCE_TOKEN_SIZE); + g_memcpy(sealed_buffer + LICENCE_TOKEN_SIZE, hwid, LICENCE_HWID_SIZE); + rdp_sec_sign(out_sig, 16, self->licence_sign_key, 16, sealed_buffer, + sizeof(sealed_buffer)); + /* Now encrypt the HWID */ + ssl_rc4_set_key(crypt_key, self->licence_key, 16); + g_memcpy(crypt_hwid, hwid, LICENCE_HWID_SIZE); + ssl_rc4_crypt(crypt_key, crypt_hwid, LICENCE_HWID_SIZE); + rdp_lic_send_authresp(self, out_token, crypt_hwid, out_sig); + ssl_rc4_info_delete(crypt_key); } /*****************************************************************************/ /* Process an licence issue packet */ static void APP_CC -rdp_lic_process_issue(struct rdp_lic* self, struct stream* s) +rdp_lic_process_issue(struct rdp_lic *self, struct stream *s) { - void* crypt_key; - int length; - int check; - int i; + void *crypt_key; + int length; + int check; + int i; + + in_uint8s(s, 2); /* 3d 45 - unknown */ + in_uint16_le(s, length); - in_uint8s(s, 2); /* 3d 45 - unknown */ - in_uint16_le(s, length); - if (!s_check_rem(s, length)) - { - return; - } - crypt_key = ssl_rc4_info_create(); - ssl_rc4_set_key(crypt_key, self->licence_key, 16); - ssl_rc4_crypt(crypt_key, s->p, length); - ssl_rc4_info_delete(crypt_key); - in_uint16_le(s, check); - if (check != 0) - { - return; - } - self->licence_issued = 1; - in_uint8s(s, 2); /* pad */ - /* advance to fourth string */ - length = 0; - for (i = 0; i < 4; i++) - { - in_uint8s(s, length); - in_uint32_le(s, length); if (!s_check_rem(s, length)) { - return; + return; } - } - /* todo save_licence(s->p, length); */ + + crypt_key = ssl_rc4_info_create(); + ssl_rc4_set_key(crypt_key, self->licence_key, 16); + ssl_rc4_crypt(crypt_key, s->p, length); + ssl_rc4_info_delete(crypt_key); + in_uint16_le(s, check); + + if (check != 0) + { + return; + } + + self->licence_issued = 1; + in_uint8s(s, 2); /* pad */ + /* advance to fourth string */ + length = 0; + + for (i = 0; i < 4; i++) + { + in_uint8s(s, length); + in_uint32_le(s, length); + + if (!s_check_rem(s, length)) + { + return; + } + } + + /* todo save_licence(s->p, length); */ } /******************************************************************************/ /* Process a licence packet */ void APP_CC -rdp_lic_process(struct rdp_lic* self, struct stream* s) +rdp_lic_process(struct rdp_lic *self, struct stream *s) { - int tag; + int tag; - in_uint8(s, tag); - in_uint8s(s, 3); /* version, length */ - switch (tag) - { - case LICENCE_TAG_DEMAND: - rdp_lic_process_demand(self, s); - break; - case LICENCE_TAG_AUTHREQ: - rdp_lic_process_authreq(self, s); - break; - case LICENCE_TAG_ISSUE: - rdp_lic_process_issue(self, s); - break; - case LICENCE_TAG_REISSUE: - case LICENCE_TAG_RESULT: - break; - default: - break; - /* todo unimpl("licence tag 0x%x\n", tag); */ - } + in_uint8(s, tag); + in_uint8s(s, 3); /* version, length */ + + switch (tag) + { + case LICENCE_TAG_DEMAND: + rdp_lic_process_demand(self, s); + break; + case LICENCE_TAG_AUTHREQ: + rdp_lic_process_authreq(self, s); + break; + case LICENCE_TAG_ISSUE: + rdp_lic_process_issue(self, s); + break; + case LICENCE_TAG_REISSUE: + case LICENCE_TAG_RESULT: + break; + default: + break; + /* todo unimpl("licence tag 0x%x\n", tag); */ + } } diff --git a/rdp/rdp_mcs.c b/rdp/rdp_mcs.c index 4b8993da..3f5162f3 100644 --- a/rdp/rdp_mcs.c +++ b/rdp/rdp_mcs.c @@ -1,562 +1,628 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp mcs layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * librdp mcs layer + */ #include "rdp.h" /*****************************************************************************/ -struct rdp_mcs* APP_CC -rdp_mcs_create(struct rdp_sec* owner, - struct stream* client_mcs_data, - struct stream* server_mcs_data) +struct rdp_mcs *APP_CC +rdp_mcs_create(struct rdp_sec *owner, + struct stream *client_mcs_data, + struct stream *server_mcs_data) { - struct rdp_mcs* self; + struct rdp_mcs *self; - self = (struct rdp_mcs*)g_malloc(sizeof(struct rdp_mcs), 1); - self->sec_layer = owner; - self->userid = 1; - self->client_mcs_data = client_mcs_data; - self->server_mcs_data = server_mcs_data; - self->iso_layer = rdp_iso_create(self); - return self; + self = (struct rdp_mcs *)g_malloc(sizeof(struct rdp_mcs), 1); + self->sec_layer = owner; + self->userid = 1; + self->client_mcs_data = client_mcs_data; + self->server_mcs_data = server_mcs_data; + self->iso_layer = rdp_iso_create(self); + return self; } /*****************************************************************************/ void APP_CC -rdp_mcs_delete(struct rdp_mcs* self) +rdp_mcs_delete(struct rdp_mcs *self) { - if (self == 0) - { - return; - } - rdp_iso_delete(self->iso_layer); - g_free(self); -} - -/*****************************************************************************/ -/* returns error */ -int APP_CC -rdp_mcs_recv(struct rdp_mcs* self, struct stream* s, int* chan) -{ - int appid; - int opcode; - int len; - - DEBUG((" in rdp_mcs_recv")); - if (rdp_iso_recv(self->iso_layer, s) != 0) - { - return 1; - } - in_uint8(s, opcode); - appid = opcode >> 2; - if (appid != MCS_SDIN) - { - DEBUG((" out rdp_mcs_recv error")); - return 1; - } - in_uint8s(s, 2); - in_uint16_be(s, *chan); - in_uint8s(s, 1); - in_uint8(s, len); - if (len & 0x80) - { - in_uint8s(s, 1); - } - DEBUG((" out rdp_mcs_recv")); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_ber_out_header(struct rdp_mcs* self, struct stream* s, - int tag_val, int len) -{ - if (tag_val > 0xff) - { - out_uint16_be(s, tag_val); - } - else - { - out_uint8(s, tag_val); - } - if (len >= 0x80) - { - out_uint8(s, 0x82); - out_uint16_be(s, len); - } - else - { - out_uint8(s, len); - } - return 0; -} - -#if 0 -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_ber_out_int8(struct rdp_mcs* self, struct stream* s, int value) -{ - rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); - out_uint8(s, value); - return 0; -} -#endif - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_ber_out_int16(struct rdp_mcs* self, struct stream* s, int value) -{ - rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 2); - out_uint8(s, (value >> 8)); - out_uint8(s, value); - return 0; -} - -#if 0 -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_ber_out_int24(struct rdp_mcs* self, struct stream* s, int value) -{ - rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 3); - out_uint8(s, (value >> 16)); - out_uint8(s, (value >> 8)); - out_uint8(s, value); - return 0; -} -#endif - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_out_domain_params(struct rdp_mcs* self, struct stream* s, - int max_channels, - int max_users, int max_tokens, - int max_pdu_size) -{ - rdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 32); - rdp_mcs_ber_out_int16(self, s, max_channels); - rdp_mcs_ber_out_int16(self, s, max_users); - rdp_mcs_ber_out_int16(self, s, max_tokens); - rdp_mcs_ber_out_int16(self, s, 1); - rdp_mcs_ber_out_int16(self, s, 0); - rdp_mcs_ber_out_int16(self, s, 1); - rdp_mcs_ber_out_int16(self, s, max_pdu_size); - rdp_mcs_ber_out_int16(self, s, 2); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_send_connection_initial(struct rdp_mcs* self) -{ - int data_len; - int len; - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - data_len = self->client_mcs_data->end - self->client_mcs_data->data; - len = 7 + 3 * 34 + 4 + data_len; - if (rdp_iso_init(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - rdp_mcs_ber_out_header(self, s, MCS_CONNECT_INITIAL, len); - rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, 0); /* calling domain */ - rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, 0); /* called domain */ - rdp_mcs_ber_out_header(self, s, BER_TAG_BOOLEAN, 1); - out_uint8(s, 0xff); /* upward flag */ - rdp_mcs_out_domain_params(self, s, 2, 2, 0, 0xffff); /* target params */ - rdp_mcs_out_domain_params(self, s, 1, 1, 1, 0x420); /* min params */ - rdp_mcs_out_domain_params(self, s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */ - rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len); - out_uint8p(s, self->client_mcs_data->data, data_len); - s_mark_end(s); - if (rdp_iso_send(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_ber_parse_header(struct rdp_mcs* self, struct stream* s, - int tag_val, int* len) -{ - int tag; - int l; - int i; - - if (tag_val > 0xff) - { - in_uint16_be(s, tag); - } - else - { - in_uint8(s, tag); - } - if (tag != tag_val) - { - return 1; - } - in_uint8(s, l); - if (l & 0x80) - { - l = l & ~0x80; - *len = 0; - while (l > 0) + if (self == 0) { - in_uint8(s, i); - *len = (*len << 8) | i; - l--; + return; } - } - else - { - *len = l; - } - if (s_check(s)) - { - return 0; - } - else - { - return 1; - } -} -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_parse_domain_params(struct rdp_mcs* self, struct stream* s) -{ - int len; - - if (rdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0) - { - return 1; - } - in_uint8s(s, len); - if (s_check(s)) - { - return 0; - } - else - { - return 1; - } -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_recv_connection_response(struct rdp_mcs* self) -{ - int len; - int res; - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (rdp_iso_recv(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - rdp_mcs_ber_parse_header(self, s, MCS_CONNECT_RESPONSE, &len); - rdp_mcs_ber_parse_header(self, s, BER_TAG_RESULT, &len); - in_uint8(s, res); - if (res != 0) - { - free_stream(s); - return 1; - } - rdp_mcs_ber_parse_header(self, s, BER_TAG_INTEGER, &len); - in_uint8s(s, len); /* connect id */ - rdp_mcs_parse_domain_params(self, s); - rdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len); - if (len > self->server_mcs_data->size) - { - len = self->server_mcs_data->size; - } - in_uint8a(s, self->server_mcs_data->data, len); - self->server_mcs_data->p = self->server_mcs_data->data; - self->server_mcs_data->end = self->server_mcs_data->data + len; - if (s_check_end(s)) - { - free_stream(s); - return 0; - } - else - { - free_stream(s); - return 1; - } -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_send_edrq(struct rdp_mcs* self) -{ - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (rdp_iso_init(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - out_uint8(s, (MCS_EDRQ << 2)); - out_uint16_be(s, 0x100); /* height */ - out_uint16_be(s, 0x100); /* interval */ - s_mark_end(s); - if (rdp_iso_send(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_send_aurq(struct rdp_mcs* self) -{ - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (rdp_iso_init(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - out_uint8(s, (MCS_AURQ << 2)); - s_mark_end(s); - if (rdp_iso_send(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_recv_aucf(struct rdp_mcs* self) -{ - int opcode; - int res; - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (rdp_iso_recv(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - in_uint8(s, opcode); - if ((opcode >> 2) != MCS_AUCF) - { - free_stream(s); - return 1; - } - in_uint8(s, res); - if (res != 0) - { - free_stream(s); - return 1; - } - if (opcode & 2) - { - in_uint16_be(s, self->userid); - } - if (!(s_check_end(s))) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_send_cjrq(struct rdp_mcs* self, int chanid) -{ - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (rdp_iso_init(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - out_uint8(s, (MCS_CJRQ << 2)); - out_uint16_be(s, self->userid); - out_uint16_be(s, chanid); - s_mark_end(s); - if (rdp_iso_send(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; -} - -/*****************************************************************************/ -/* returns error */ -static int APP_CC -rdp_mcs_recv_cjcf(struct rdp_mcs* self) -{ - int opcode; - int res; - struct stream* s; - - make_stream(s); - init_stream(s, 8192); - if (rdp_iso_recv(self->iso_layer, s) != 0) - { - free_stream(s); - return 1; - } - in_uint8(s, opcode); - if ((opcode >> 2) != MCS_CJCF) - { - free_stream(s); - return 1; - } - in_uint8(s, res); - if (res != 0) - { - free_stream(s); - return 1; - } - in_uint8s(s, 4); /* mcs_userid, req_chanid */ - if (opcode & 2) - { - in_uint8s(s, 2); /* join_chanid */ - } - if (!(s_check_end(s))) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; + rdp_iso_delete(self->iso_layer); + g_free(self); } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_mcs_connect(struct rdp_mcs* self, char* ip, char* port) +rdp_mcs_recv(struct rdp_mcs *self, struct stream *s, int *chan) { - DEBUG((" in rdp_mcs_connect")); - if (rdp_iso_connect(self->iso_layer, ip, port) != 0) - { - DEBUG((" out rdp_mcs_connect error rdp_iso_connect failed")); - return 1; - } - rdp_mcs_send_connection_initial(self); - if (rdp_mcs_recv_connection_response(self) != 0) - { - rdp_iso_disconnect(self->iso_layer); - DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_connection_response \ + int appid; + int opcode; + int len; + + DEBUG((" in rdp_mcs_recv")); + + if (rdp_iso_recv(self->iso_layer, s) != 0) + { + return 1; + } + + in_uint8(s, opcode); + appid = opcode >> 2; + + if (appid != MCS_SDIN) + { + DEBUG((" out rdp_mcs_recv error")); + return 1; + } + + in_uint8s(s, 2); + in_uint16_be(s, *chan); + in_uint8s(s, 1); + in_uint8(s, len); + + if (len & 0x80) + { + in_uint8s(s, 1); + } + + DEBUG((" out rdp_mcs_recv")); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_ber_out_header(struct rdp_mcs *self, struct stream *s, + int tag_val, int len) +{ + if (tag_val > 0xff) + { + out_uint16_be(s, tag_val); + } + else + { + out_uint8(s, tag_val); + } + + if (len >= 0x80) + { + out_uint8(s, 0x82); + out_uint16_be(s, len); + } + else + { + out_uint8(s, len); + } + + return 0; +} + +#if 0 +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_ber_out_int8(struct rdp_mcs *self, struct stream *s, int value) +{ + rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1); + out_uint8(s, value); + return 0; +} +#endif + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_ber_out_int16(struct rdp_mcs *self, struct stream *s, int value) +{ + rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 2); + out_uint8(s, (value >> 8)); + out_uint8(s, value); + return 0; +} + +#if 0 +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_ber_out_int24(struct rdp_mcs *self, struct stream *s, int value) +{ + rdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 3); + out_uint8(s, (value >> 16)); + out_uint8(s, (value >> 8)); + out_uint8(s, value); + return 0; +} +#endif + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_out_domain_params(struct rdp_mcs *self, struct stream *s, + int max_channels, + int max_users, int max_tokens, + int max_pdu_size) +{ + rdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 32); + rdp_mcs_ber_out_int16(self, s, max_channels); + rdp_mcs_ber_out_int16(self, s, max_users); + rdp_mcs_ber_out_int16(self, s, max_tokens); + rdp_mcs_ber_out_int16(self, s, 1); + rdp_mcs_ber_out_int16(self, s, 0); + rdp_mcs_ber_out_int16(self, s, 1); + rdp_mcs_ber_out_int16(self, s, max_pdu_size); + rdp_mcs_ber_out_int16(self, s, 2); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_send_connection_initial(struct rdp_mcs *self) +{ + int data_len; + int len; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + data_len = self->client_mcs_data->end - self->client_mcs_data->data; + len = 7 + 3 * 34 + 4 + data_len; + + if (rdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + rdp_mcs_ber_out_header(self, s, MCS_CONNECT_INITIAL, len); + rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, 0); /* calling domain */ + rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, 0); /* called domain */ + rdp_mcs_ber_out_header(self, s, BER_TAG_BOOLEAN, 1); + out_uint8(s, 0xff); /* upward flag */ + rdp_mcs_out_domain_params(self, s, 2, 2, 0, 0xffff); /* target params */ + rdp_mcs_out_domain_params(self, s, 1, 1, 1, 0x420); /* min params */ + rdp_mcs_out_domain_params(self, s, 0xffff, 0xfc17, 0xffff, 0xffff); /* max params */ + rdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len); + out_uint8p(s, self->client_mcs_data->data, data_len); + s_mark_end(s); + + if (rdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_ber_parse_header(struct rdp_mcs *self, struct stream *s, + int tag_val, int *len) +{ + int tag; + int l; + int i; + + if (tag_val > 0xff) + { + in_uint16_be(s, tag); + } + else + { + in_uint8(s, tag); + } + + if (tag != tag_val) + { + return 1; + } + + in_uint8(s, l); + + if (l & 0x80) + { + l = l & ~0x80; + *len = 0; + + while (l > 0) + { + in_uint8(s, i); + *len = (*len << 8) | i; + l--; + } + } + else + { + *len = l; + } + + if (s_check(s)) + { + return 0; + } + else + { + return 1; + } +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_parse_domain_params(struct rdp_mcs *self, struct stream *s) +{ + int len; + + if (rdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0) + { + return 1; + } + + in_uint8s(s, len); + + if (s_check(s)) + { + return 0; + } + else + { + return 1; + } +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_recv_connection_response(struct rdp_mcs *self) +{ + int len; + int res; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (rdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + rdp_mcs_ber_parse_header(self, s, MCS_CONNECT_RESPONSE, &len); + rdp_mcs_ber_parse_header(self, s, BER_TAG_RESULT, &len); + in_uint8(s, res); + + if (res != 0) + { + free_stream(s); + return 1; + } + + rdp_mcs_ber_parse_header(self, s, BER_TAG_INTEGER, &len); + in_uint8s(s, len); /* connect id */ + rdp_mcs_parse_domain_params(self, s); + rdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len); + + if (len > self->server_mcs_data->size) + { + len = self->server_mcs_data->size; + } + + in_uint8a(s, self->server_mcs_data->data, len); + self->server_mcs_data->p = self->server_mcs_data->data; + self->server_mcs_data->end = self->server_mcs_data->data + len; + + if (s_check_end(s)) + { + free_stream(s); + return 0; + } + else + { + free_stream(s); + return 1; + } +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_send_edrq(struct rdp_mcs *self) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (rdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint8(s, (MCS_EDRQ << 2)); + out_uint16_be(s, 0x100); /* height */ + out_uint16_be(s, 0x100); /* interval */ + s_mark_end(s); + + if (rdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_send_aurq(struct rdp_mcs *self) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (rdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint8(s, (MCS_AURQ << 2)); + s_mark_end(s); + + if (rdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_recv_aucf(struct rdp_mcs *self) +{ + int opcode; + int res; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (rdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + in_uint8(s, opcode); + + if ((opcode >> 2) != MCS_AUCF) + { + free_stream(s); + return 1; + } + + in_uint8(s, res); + + if (res != 0) + { + free_stream(s); + return 1; + } + + if (opcode & 2) + { + in_uint16_be(s, self->userid); + } + + if (!(s_check_end(s))) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_send_cjrq(struct rdp_mcs *self, int chanid) +{ + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (rdp_iso_init(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + out_uint8(s, (MCS_CJRQ << 2)); + out_uint16_be(s, self->userid); + out_uint16_be(s, chanid); + s_mark_end(s); + + if (rdp_iso_send(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +static int APP_CC +rdp_mcs_recv_cjcf(struct rdp_mcs *self) +{ + int opcode; + int res; + struct stream *s; + + make_stream(s); + init_stream(s, 8192); + + if (rdp_iso_recv(self->iso_layer, s) != 0) + { + free_stream(s); + return 1; + } + + in_uint8(s, opcode); + + if ((opcode >> 2) != MCS_CJCF) + { + free_stream(s); + return 1; + } + + in_uint8(s, res); + + if (res != 0) + { + free_stream(s); + return 1; + } + + in_uint8s(s, 4); /* mcs_userid, req_chanid */ + + if (opcode & 2) + { + in_uint8s(s, 2); /* join_chanid */ + } + + if (!(s_check_end(s))) + { + free_stream(s); + return 1; + } + + free_stream(s); + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +rdp_mcs_connect(struct rdp_mcs *self, char *ip, char *port) +{ + DEBUG((" in rdp_mcs_connect")); + + if (rdp_iso_connect(self->iso_layer, ip, port) != 0) + { + DEBUG((" out rdp_mcs_connect error rdp_iso_connect failed")); + return 1; + } + + rdp_mcs_send_connection_initial(self); + + if (rdp_mcs_recv_connection_response(self) != 0) + { + rdp_iso_disconnect(self->iso_layer); + DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_connection_response \ failed")); - return 1; - } - rdp_mcs_send_edrq(self); - rdp_mcs_send_aurq(self); - if (rdp_mcs_recv_aucf(self) != 0) - { - rdp_iso_disconnect(self->iso_layer); - DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_aucf failed")); - return 1; - } - rdp_mcs_send_cjrq(self, self->userid + 1001); - if (rdp_mcs_recv_cjcf(self) != 0) - { - rdp_iso_disconnect(self->iso_layer); - DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_cjcf 1 failed")); - return 1; - } - rdp_mcs_send_cjrq(self, MCS_GLOBAL_CHANNEL); - if (rdp_mcs_recv_cjcf(self) != 0) - { - rdp_iso_disconnect(self->iso_layer); - DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_cjcf 2 failed")); - return 1; - } - DEBUG((" out rdp_mcs_connect")); - return 0; + return 1; + } + + rdp_mcs_send_edrq(self); + rdp_mcs_send_aurq(self); + + if (rdp_mcs_recv_aucf(self) != 0) + { + rdp_iso_disconnect(self->iso_layer); + DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_aucf failed")); + return 1; + } + + rdp_mcs_send_cjrq(self, self->userid + 1001); + + if (rdp_mcs_recv_cjcf(self) != 0) + { + rdp_iso_disconnect(self->iso_layer); + DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_cjcf 1 failed")); + return 1; + } + + rdp_mcs_send_cjrq(self, MCS_GLOBAL_CHANNEL); + + if (rdp_mcs_recv_cjcf(self) != 0) + { + rdp_iso_disconnect(self->iso_layer); + DEBUG((" out rdp_mcs_connect error rdp_mcs_recv_cjcf 2 failed")); + return 1; + } + + DEBUG((" out rdp_mcs_connect")); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_mcs_init(struct rdp_mcs* self, struct stream* s) +rdp_mcs_init(struct rdp_mcs *self, struct stream *s) { - rdp_iso_init(self->iso_layer, s); - s_push_layer(s, mcs_hdr, 8); - return 0; + rdp_iso_init(self->iso_layer, s); + s_push_layer(s, mcs_hdr, 8); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_mcs_send(struct rdp_mcs* self, struct stream* s) +rdp_mcs_send(struct rdp_mcs *self, struct stream *s) { - int len; + int len; - s_pop_layer(s, mcs_hdr); - len = (s->end - s->p) - 8; - len = len | 0x8000; - out_uint8(s, MCS_SDRQ << 2); - out_uint16_be(s, self->userid); - out_uint16_be(s, MCS_GLOBAL_CHANNEL); - out_uint8(s, 0x70); - out_uint16_be(s, len); - if (rdp_iso_send(self->iso_layer, s) != 0) - { - return 1; - } - return 0; + s_pop_layer(s, mcs_hdr); + len = (s->end - s->p) - 8; + len = len | 0x8000; + out_uint8(s, MCS_SDRQ << 2); + out_uint16_be(s, self->userid); + out_uint16_be(s, MCS_GLOBAL_CHANNEL); + out_uint8(s, 0x70); + out_uint16_be(s, len); + + if (rdp_iso_send(self->iso_layer, s) != 0) + { + return 1; + } + + return 0; } diff --git a/rdp/rdp_orders.c b/rdp/rdp_orders.c index c0da6c35..b686c925 100644 --- a/rdp/rdp_orders.c +++ b/rdp/rdp_orders.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp orders - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ibrdp orders + */ #include "rdp.h" @@ -27,1506 +25,1668 @@ #endif /*****************************************************************************/ -struct rdp_orders* APP_CC -rdp_orders_create(struct rdp_rdp* owner) +struct rdp_orders *APP_CC +rdp_orders_create(struct rdp_rdp *owner) { - struct rdp_orders* self = (struct rdp_orders *)NULL; + struct rdp_orders *self = (struct rdp_orders *)NULL; - self = (struct rdp_orders*)g_malloc(sizeof(struct rdp_orders), 1); - self->rdp_layer = owner; - return self; + self = (struct rdp_orders *)g_malloc(sizeof(struct rdp_orders), 1); + self->rdp_layer = owner; + return self; } /*****************************************************************************/ void APP_CC -rdp_orders_delete(struct rdp_orders* self) +rdp_orders_delete(struct rdp_orders *self) { - int i = 0; - int j = 0; + int i = 0; + int j = 0; - if (self == 0) - { - return; - } - /* free the colormap cache */ - for (i = 0; i < 6; i++) - { - g_free(self->cache_colormap[i]); - } - /* free the bitmap cache */ - for (i = 0; i < 3; i++) - { - for (j = 0; j < 600; j++) + if (self == 0) { - if (self->cache_bitmap[i][j] != 0) - { - g_free(self->cache_bitmap[i][j]->data); - } - g_free(self->cache_bitmap[i][j]); + return; } - } - g_free(self); + + /* free the colormap cache */ + for (i = 0; i < 6; i++) + { + g_free(self->cache_colormap[i]); + } + + /* free the bitmap cache */ + for (i = 0; i < 3; i++) + { + for (j = 0; j < 600; j++) + { + if (self->cache_bitmap[i][j] != 0) + { + g_free(self->cache_bitmap[i][j]->data); + } + + g_free(self->cache_bitmap[i][j]); + } + } + + g_free(self); } /*****************************************************************************/ void APP_CC -rdp_orders_reset_state(struct rdp_orders* self) +rdp_orders_reset_state(struct rdp_orders *self) { - g_memset(&self->state, 0, sizeof(self->state)); + g_memset(&self->state, 0, sizeof(self->state)); } /*****************************************************************************/ /* Read field indicating which parameters are present */ static void APP_CC -rdp_orders_in_present(struct stream* s, int* present, +rdp_orders_in_present(struct stream *s, int *present, int flags, int size) { - int bits = 0; - int i = 0; + int bits = 0; + int i = 0; - if (flags & RDP_ORDER_SMALL) - { - size--; - } - if (flags & RDP_ORDER_TINY) - { - if (size < 2) + if (flags & RDP_ORDER_SMALL) { - size = 0; + size--; } - else + + if (flags & RDP_ORDER_TINY) { - size -= 2; + if (size < 2) + { + size = 0; + } + else + { + size -= 2; + } + } + + *present = 0; + + for (i = 0; i < size; i++) + { + in_uint8(s, bits); + *present |= bits << (i * 8); } - } - *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 APP_CC -rdp_orders_in_coord(struct stream* s, int* coord, int delta) +rdp_orders_in_coord(struct stream *s, int *coord, int delta) { - int change = 0; + int change = 0; - if (delta) - { - in_sint8(s, change); - *coord += change; - } - else - { - in_sint16_le(s, *coord); - } + if (delta) + { + in_sint8(s, change); + *coord += change; + } + else + { + in_sint16_le(s, *coord); + } } /*****************************************************************************/ /* Parse bounds information */ static void APP_CC -rdp_orders_parse_bounds(struct rdp_orders* self, struct stream* s) +rdp_orders_parse_bounds(struct rdp_orders *self, struct stream *s) { - int present = 0; + int present = 0; - in_uint8(s, present); - if (present & 1) - { - rdp_orders_in_coord(s, &self->state.clip_left, 0); - } - else if (present & 16) - { - rdp_orders_in_coord(s, &self->state.clip_left, 1); - } - if (present & 2) - { - rdp_orders_in_coord(s, &self->state.clip_top, 0); - } - else if (present & 32) - { - rdp_orders_in_coord(s, &self->state.clip_top, 1); - } - if (present & 4) - { - rdp_orders_in_coord(s, &self->state.clip_right, 0); - } - else if (present & 64) - { - rdp_orders_in_coord(s, &self->state.clip_right, 1); - } - if (present & 8) - { - rdp_orders_in_coord(s, &self->state.clip_bottom, 0); - } - else if (present & 128) - { - rdp_orders_in_coord(s, &self->state.clip_bottom, 1); - } + in_uint8(s, present); + + if (present & 1) + { + rdp_orders_in_coord(s, &self->state.clip_left, 0); + } + else if (present & 16) + { + rdp_orders_in_coord(s, &self->state.clip_left, 1); + } + + if (present & 2) + { + rdp_orders_in_coord(s, &self->state.clip_top, 0); + } + else if (present & 32) + { + rdp_orders_in_coord(s, &self->state.clip_top, 1); + } + + if (present & 4) + { + rdp_orders_in_coord(s, &self->state.clip_right, 0); + } + else if (present & 64) + { + rdp_orders_in_coord(s, &self->state.clip_right, 1); + } + + if (present & 8) + { + rdp_orders_in_coord(s, &self->state.clip_bottom, 0); + } + else if (present & 128) + { + rdp_orders_in_coord(s, &self->state.clip_bottom, 1); + } } /*****************************************************************************/ /* Process a colormap cache order */ static void APP_CC -rdp_orders_process_colcache(struct rdp_orders* self, struct stream* s, +rdp_orders_process_colcache(struct rdp_orders *self, struct stream *s, int flags) { - struct rdp_colormap* colormap = (struct rdp_colormap *)NULL; - struct stream* rec_s = (struct stream *)NULL; - int cache_id = 0; - int i = 0; + struct rdp_colormap *colormap = (struct rdp_colormap *)NULL; + struct stream *rec_s = (struct stream *)NULL; + int cache_id = 0; + int i = 0; - colormap = (struct rdp_colormap*)g_malloc(sizeof(struct rdp_colormap), 1); - in_uint8(s, cache_id); - in_uint16_le(s, colormap->ncolors); - for (i = 0; i < colormap->ncolors; i++) - { - in_uint32_le(s, colormap->colors[i]); - } - g_free(self->cache_colormap[cache_id]); - self->cache_colormap[cache_id] = colormap; - if (self->rdp_layer->rec_mode) - { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, 4096); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 10); - out_uint8(rec_s, cache_id); - for (i = 0; i < 256; i++) + colormap = (struct rdp_colormap *)g_malloc(sizeof(struct rdp_colormap), 1); + in_uint8(s, cache_id); + in_uint16_le(s, colormap->ncolors); + + for (i = 0; i < colormap->ncolors; i++) { - out_uint32_le(rec_s, colormap->colors[i]); + in_uint32_le(s, colormap->colors[i]); + } + + g_free(self->cache_colormap[cache_id]); + self->cache_colormap[cache_id] = colormap; + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, 4096); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 10); + out_uint8(rec_s, cache_id); + + for (i = 0; i < 256; i++) + { + out_uint32_le(rec_s, colormap->colors[i]); + } + + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); } - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } } /*****************************************************************************/ /* Process a raw bitmap cache order */ static void APP_CC -rdp_orders_process_raw_bmpcache(struct rdp_orders* self, struct stream* s, +rdp_orders_process_raw_bmpcache(struct rdp_orders *self, struct stream *s, int flags) { - int cache_idx = 0; - int bufsize = 0; - int cache_id = 0; - int width = 0; - int height = 0; - int bpp = 0; - int Bpp = 0; - int x = 0; - int y = 0; - char* inverted = (char *)NULL; - char* dst = (char *)NULL; - struct rdp_bitmap* bitmap = (struct rdp_bitmap *)NULL; - struct stream* rec_s = (struct stream *)NULL; + int cache_idx = 0; + int bufsize = 0; + int cache_id = 0; + int width = 0; + int height = 0; + int bpp = 0; + int Bpp = 0; + int x = 0; + int y = 0; + char *inverted = (char *)NULL; + char *dst = (char *)NULL; + struct rdp_bitmap *bitmap = (struct rdp_bitmap *)NULL; + struct stream *rec_s = (struct stream *)NULL; - in_uint8(s, cache_id); - in_uint8s(s, 1); - 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); - inverted = (char*)g_malloc(width * height * Bpp, 0); - for (y = 0; y < height; y++) - { - dst = inverted + (((height - y) - 1) * (width * Bpp)); - if (Bpp == 1) + in_uint8(s, cache_id); + in_uint8s(s, 1); + 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); + inverted = (char *)g_malloc(width * height * Bpp, 0); + + for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) - { - in_uint8(s, dst[x]); - } + dst = inverted + (((height - y) - 1) * (width * Bpp)); + + if (Bpp == 1) + { + for (x = 0; x < width; x++) + { + in_uint8(s, dst[x]); + } + } + else if (Bpp == 2) + { + for (x = 0; x < width; x++) + { + in_uint16_le(s, ((tui16 *)dst)[x]); + } + } + else if (Bpp == 3) + { + for (x = 0; x < width; x++) + { + in_uint8(s, dst[x * 3 + 0]); + in_uint8(s, dst[x * 3 + 1]); + in_uint8(s, dst[x * 3 + 2]); + } + } } - else if (Bpp == 2) + + bitmap = (struct rdp_bitmap *)g_malloc(sizeof(struct rdp_bitmap), 0); + bitmap->width = width; + bitmap->height = height; + bitmap->bpp = bpp; + bitmap->data = inverted; + + if (self->cache_bitmap[cache_id][cache_idx] != 0) { - for (x = 0; x < width; x++) - { - in_uint16_le(s, ((tui16*)dst)[x]); - } + g_free(self->cache_bitmap[cache_id][cache_idx]->data); } - else if (Bpp == 3) + + g_free(self->cache_bitmap[cache_id][cache_idx]); + self->cache_bitmap[cache_id][cache_idx] = bitmap; + + if (self->rdp_layer->rec_mode) { - for (x = 0; x < width; x++) - { - in_uint8(s, dst[x * 3 + 0]); - in_uint8(s, dst[x * 3 + 1]); - in_uint8(s, dst[x * 3 + 2]); - } + y = width * height * Bpp; + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, y + 256); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 8); + out_uint8(rec_s, cache_id); + out_uint16_le(rec_s, cache_idx); + out_uint16_le(rec_s, width); + out_uint16_le(rec_s, height); + out_uint16_le(rec_s, y); + out_uint8a(rec_s, inverted, y); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); } - } - bitmap = (struct rdp_bitmap*)g_malloc(sizeof(struct rdp_bitmap), 0); - bitmap->width = width; - bitmap->height = height; - bitmap->bpp = bpp; - bitmap->data = inverted; - if (self->cache_bitmap[cache_id][cache_idx] != 0) - { - g_free(self->cache_bitmap[cache_id][cache_idx]->data); - } - g_free(self->cache_bitmap[cache_id][cache_idx]); - self->cache_bitmap[cache_id][cache_idx] = bitmap; - if (self->rdp_layer->rec_mode) - { - y = width * height * Bpp; - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, y + 256); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 8); - out_uint8(rec_s, cache_id); - out_uint16_le(rec_s, cache_idx); - out_uint16_le(rec_s, width); - out_uint16_le(rec_s, height); - out_uint16_le(rec_s, y); - out_uint8a(rec_s, inverted, y); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } } /*****************************************************************************/ /* Process a bitmap cache order */ static void APP_CC -rdp_orders_process_bmpcache(struct rdp_orders* self, struct stream* s, +rdp_orders_process_bmpcache(struct rdp_orders *self, struct stream *s, int flags) { - char* data = (char *)NULL; - char* bmpdata = (char *)NULL; - int cache_idx = 0; - int size = 0; - int cache_id = 0; - int width = 0; - int height = 0; - int bpp = 0; - int Bpp = 0; - int bufsize = 0; - int pad1 = 0; - int pad2 = 0; - int row_size = 0; - int final_size = 0; - struct rdp_bitmap* bitmap = (struct rdp_bitmap *)NULL; - struct stream* rec_s = (struct stream *)NULL; + char *data = (char *)NULL; + char *bmpdata = (char *)NULL; + int cache_idx = 0; + int size = 0; + int cache_id = 0; + int width = 0; + int height = 0; + int bpp = 0; + int Bpp = 0; + int bufsize = 0; + int pad1 = 0; + int pad2 = 0; + int row_size = 0; + int final_size = 0; + struct rdp_bitmap *bitmap = (struct rdp_bitmap *)NULL; + struct stream *rec_s = (struct stream *)NULL; - in_uint8(s, cache_id); - in_uint8(s, pad1); - 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); - if (flags & 1024) - { - size = bufsize; - } - else - { - in_uint16_le(s, pad2); - in_uint16_le(s, size); - in_uint16_le(s, row_size); - in_uint16_le(s, final_size); - } - in_uint8p(s, data, size); - bmpdata = (char*)g_malloc(width * height * Bpp, 0); - if (rdp_bitmap_decompress(bmpdata, width, height, data, size, Bpp)) - { - } - else - { - /* error */ - } - bitmap = (struct rdp_bitmap*)g_malloc(sizeof(struct rdp_bitmap), 0); - bitmap->width = width; - bitmap->height = height; - bitmap->bpp = bpp; - bitmap->data = bmpdata; - if (self->cache_bitmap[cache_id][cache_idx] != 0) - { - g_free(self->cache_bitmap[cache_id][cache_idx]->data); - } - g_free(self->cache_bitmap[cache_id][cache_idx]); - self->cache_bitmap[cache_id][cache_idx] = bitmap; - if (self->rdp_layer->rec_mode) - { - size = width * height * Bpp; - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, size + 256); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 8); - out_uint8(rec_s, cache_id); - out_uint16_le(rec_s, cache_idx); - out_uint16_le(rec_s, width); - out_uint16_le(rec_s, height); - out_uint16_le(rec_s, size); - out_uint8a(rec_s, bmpdata, size); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } + in_uint8(s, cache_id); + in_uint8(s, pad1); + 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); + + if (flags & 1024) + { + size = bufsize; + } + else + { + in_uint16_le(s, pad2); + in_uint16_le(s, size); + in_uint16_le(s, row_size); + in_uint16_le(s, final_size); + } + + in_uint8p(s, data, size); + bmpdata = (char *)g_malloc(width * height * Bpp, 0); + + if (rdp_bitmap_decompress(bmpdata, width, height, data, size, Bpp)) + { + } + else + { + /* error */ + } + + bitmap = (struct rdp_bitmap *)g_malloc(sizeof(struct rdp_bitmap), 0); + bitmap->width = width; + bitmap->height = height; + bitmap->bpp = bpp; + bitmap->data = bmpdata; + + if (self->cache_bitmap[cache_id][cache_idx] != 0) + { + g_free(self->cache_bitmap[cache_id][cache_idx]->data); + } + + g_free(self->cache_bitmap[cache_id][cache_idx]); + self->cache_bitmap[cache_id][cache_idx] = bitmap; + + if (self->rdp_layer->rec_mode) + { + size = width * height * Bpp; + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, size + 256); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 8); + out_uint8(rec_s, cache_id); + out_uint16_le(rec_s, cache_idx); + out_uint16_le(rec_s, width); + out_uint16_le(rec_s, height); + out_uint16_le(rec_s, size); + out_uint8a(rec_s, bmpdata, size); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } } /*****************************************************************************/ /* Process a font cache order */ static void APP_CC -rdp_orders_process_fontcache(struct rdp_orders* self, struct stream* s, +rdp_orders_process_fontcache(struct rdp_orders *self, struct stream *s, int flags) { - struct stream* rec_s = (struct stream *)NULL; - int font = 0; - int nglyphs = 0; - int character = 0; - int offset = 0; - int baseline = 0; - int width = 0; - int height = 0; - int i = 0; - int datasize = 0; - char* data = (char *)NULL; + struct stream *rec_s = (struct stream *)NULL; + int font = 0; + int nglyphs = 0; + int character = 0; + int offset = 0; + int baseline = 0; + int width = 0; + int height = 0; + int i = 0; + int datasize = 0; + char *data = (char *)NULL; - in_uint8(s, font); - in_uint8(s, 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); - self->rdp_layer->mod->server_add_char(self->rdp_layer->mod, font, - character, offset, baseline, - width, height, data); - if (self->rdp_layer->rec_mode) + in_uint8(s, font); + in_uint8(s, nglyphs); + + for (i = 0; i < nglyphs; i++) { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, datasize + 256); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 9); - out_uint8(rec_s, font); - out_uint16_le(rec_s, character); - out_uint16_le(rec_s, offset); - out_uint16_le(rec_s, baseline); - out_uint16_le(rec_s, width); - out_uint16_le(rec_s, height); - out_uint16_le(rec_s, datasize); - out_uint8a(rec_s, data, datasize); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); + 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); + self->rdp_layer->mod->server_add_char(self->rdp_layer->mod, font, + character, offset, baseline, + width, height, data); + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, datasize + 256); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 9); + out_uint8(rec_s, font); + out_uint16_le(rec_s, character); + out_uint16_le(rec_s, offset); + out_uint16_le(rec_s, baseline); + out_uint16_le(rec_s, width); + out_uint16_le(rec_s, height); + out_uint16_le(rec_s, datasize); + out_uint8a(rec_s, data, datasize); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } } - } } /*****************************************************************************/ /* Process a secondary order */ static int APP_CC -rdp_orders_process_secondary_order(struct rdp_orders* self, struct stream* s) +rdp_orders_process_secondary_order(struct rdp_orders *self, struct stream *s) { - short length = 0; - int flags = 0; - int type = 0; - char* next_order = (char *)NULL; + short length = 0; + int flags = 0; + int type = 0; + char *next_order = (char *)NULL; - in_uint16_le(s, length); - in_uint16_le(s, flags); - in_uint8(s, type); - next_order = s->p + length + 7; - switch (type) - { - case RDP_ORDER_COLCACHE: - rdp_orders_process_colcache(self, s, flags); - break; - case RDP_ORDER_RAW_BMPCACHE: - rdp_orders_process_raw_bmpcache(self, s, flags); - break; - case RDP_ORDER_BMPCACHE: - rdp_orders_process_bmpcache(self, s, flags); - break; - case RDP_ORDER_FONTCACHE: - rdp_orders_process_fontcache(self, s, flags); - break; - default: - /* error, unknown order */ - break; - } - s->p = next_order; - return 0; + in_uint16_le(s, length); + in_uint16_le(s, flags); + in_uint8(s, type); + next_order = s->p + length + 7; + + switch (type) + { + case RDP_ORDER_COLCACHE: + rdp_orders_process_colcache(self, s, flags); + break; + case RDP_ORDER_RAW_BMPCACHE: + rdp_orders_process_raw_bmpcache(self, s, flags); + break; + case RDP_ORDER_BMPCACHE: + rdp_orders_process_bmpcache(self, s, flags); + break; + case RDP_ORDER_FONTCACHE: + rdp_orders_process_fontcache(self, s, flags); + break; + default: + /* error, unknown order */ + break; + } + + s->p = next_order; + return 0; } /*****************************************************************************/ /* Read a color entry */ static void APP_CC -rdp_orders_in_color(struct stream* s, int* color) +rdp_orders_in_color(struct stream *s, int *color) { - int i = 0; + int i = 0; - in_uint8(s, i); - *color = i; - in_uint8(s, i); - *color |= i << 8; - in_uint8(s, i); - *color |= i << 16; + in_uint8(s, i); + *color = i; + in_uint8(s, i); + *color |= i << 8; + in_uint8(s, i); + *color |= i << 16; } /*****************************************************************************/ /* Parse a brush */ static void APP_CC -rdp_orders_parse_brush(struct stream* s, struct rdp_brush* brush, int present) +rdp_orders_parse_brush(struct stream *s, struct rdp_brush *brush, int 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); - } + 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); + } } /*****************************************************************************/ /* Parse a pen */ static void APP_CC -rdp_orders_parse_pen(struct stream* s, struct rdp_pen* pen, int present) +rdp_orders_parse_pen(struct stream *s, struct rdp_pen *pen, int present) { - if (present & 1) - { - in_uint8(s, pen->style); - } - if (present & 2) - { - in_uint8(s, pen->width); - } - if (present & 4) - { - rdp_orders_in_color(s, &pen->color); - } + if (present & 1) + { + in_uint8(s, pen->style); + } + + if (present & 2) + { + in_uint8(s, pen->width); + } + + if (present & 4) + { + rdp_orders_in_color(s, &pen->color); + } } /*****************************************************************************/ /* Process a text order */ static void APP_CC -rdp_orders_process_text2(struct rdp_orders* self, struct stream* s, +rdp_orders_process_text2(struct rdp_orders *self, struct stream *s, int present, int delta) { - int fgcolor = 0; - int bgcolor = 0; - struct stream* rec_s = (struct stream *)NULL; + int fgcolor = 0; + int bgcolor = 0; + struct stream *rec_s = (struct stream *)NULL; - if (present & 0x000001) - { - in_uint8(s, self->state.text_font); - } - if (present & 0x000002) - { - in_uint8(s, self->state.text_flags); - } - if (present & 0x000004) - { - in_uint8(s, self->state.text_opcode); - } - if (present & 0x000008) - { - in_uint8(s, self->state.text_mixmode); - } - if (present & 0x000010) - { - rdp_orders_in_color(s, &self->state.text_fgcolor); - } - if (present & 0x000020) - { - rdp_orders_in_color(s, &self->state.text_bgcolor); - } - if (present & 0x000040) - { - in_sint16_le(s, self->state.text_clipleft); - } - if (present & 0x000080) - { - in_sint16_le(s, self->state.text_cliptop); - } - if (present & 0x000100) - { - in_sint16_le(s, self->state.text_clipright); - } - if (present & 0x000200) - { - in_sint16_le(s, self->state.text_clipbottom); - } - if (present & 0x000400) - { - in_sint16_le(s, self->state.text_boxleft); - } - if (present & 0x000800) - { - in_sint16_le(s, self->state.text_boxtop); - } - if (present & 0x001000) - { - in_sint16_le(s, self->state.text_boxright); - } - if (present & 0x002000) - { - in_sint16_le(s, self->state.text_boxbottom); - } - rdp_orders_parse_brush(s, &self->state.text_brush, present >> 14); - if (present & 0x080000) - { - in_sint16_le(s, self->state.text_x); - } - if (present & 0x100000) - { - in_sint16_le(s, self->state.text_y); - } - if (present & 0x200000) - { - in_uint8(s, self->state.text_length); - in_uint8a(s, self->state.text_text, self->state.text_length); - } - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, - self->state.text_opcode); - fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, - self->rdp_layer->mod->xrdp_bpp, - self->state.text_fgcolor, - self->rdp_layer->colormap.colors); - self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); - bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, - self->rdp_layer->mod->xrdp_bpp, - self->state.text_bgcolor, - self->rdp_layer->colormap.colors); - self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); - self->rdp_layer->mod->server_draw_text(self->rdp_layer->mod, - self->state.text_font, - self->state.text_flags, - self->state.text_mixmode, - self->state.text_clipleft, - self->state.text_cliptop, - self->state.text_clipright, - self->state.text_clipbottom, - self->state.text_boxleft, - self->state.text_boxtop, - self->state.text_boxright, - self->state.text_boxbottom, - self->state.text_x, - self->state.text_y, - self->state.text_text, - self->state.text_length); - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); - if (self->rdp_layer->rec_mode) - { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, 512); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 7); - out_uint8(rec_s, self->state.text_font); - out_uint8(rec_s, self->state.text_flags); - out_uint8(rec_s, self->state.text_opcode); - out_uint8(rec_s, self->state.text_mixmode); - out_uint32_le(rec_s, self->state.text_fgcolor); - out_uint32_le(rec_s, self->state.text_bgcolor); - out_uint16_le(rec_s, self->state.text_clipleft); - out_uint16_le(rec_s, self->state.text_cliptop); - out_uint16_le(rec_s, self->state.text_clipright); - out_uint16_le(rec_s, self->state.text_clipbottom); - out_uint16_le(rec_s, self->state.text_boxleft); - out_uint16_le(rec_s, self->state.text_boxtop); - out_uint16_le(rec_s, self->state.text_boxright); - out_uint16_le(rec_s, self->state.text_boxbottom); - out_uint16_le(rec_s, self->state.text_x); - out_uint16_le(rec_s, self->state.text_y); - out_uint16_le(rec_s, self->state.text_length); - out_uint8a(rec_s, self->state.text_text, self->state.text_length); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } + if (present & 0x000001) + { + in_uint8(s, self->state.text_font); + } + + if (present & 0x000002) + { + in_uint8(s, self->state.text_flags); + } + + if (present & 0x000004) + { + in_uint8(s, self->state.text_opcode); + } + + if (present & 0x000008) + { + in_uint8(s, self->state.text_mixmode); + } + + if (present & 0x000010) + { + rdp_orders_in_color(s, &self->state.text_fgcolor); + } + + if (present & 0x000020) + { + rdp_orders_in_color(s, &self->state.text_bgcolor); + } + + if (present & 0x000040) + { + in_sint16_le(s, self->state.text_clipleft); + } + + if (present & 0x000080) + { + in_sint16_le(s, self->state.text_cliptop); + } + + if (present & 0x000100) + { + in_sint16_le(s, self->state.text_clipright); + } + + if (present & 0x000200) + { + in_sint16_le(s, self->state.text_clipbottom); + } + + if (present & 0x000400) + { + in_sint16_le(s, self->state.text_boxleft); + } + + if (present & 0x000800) + { + in_sint16_le(s, self->state.text_boxtop); + } + + if (present & 0x001000) + { + in_sint16_le(s, self->state.text_boxright); + } + + if (present & 0x002000) + { + in_sint16_le(s, self->state.text_boxbottom); + } + + rdp_orders_parse_brush(s, &self->state.text_brush, present >> 14); + + if (present & 0x080000) + { + in_sint16_le(s, self->state.text_x); + } + + if (present & 0x100000) + { + in_sint16_le(s, self->state.text_y); + } + + if (present & 0x200000) + { + in_uint8(s, self->state.text_length); + in_uint8a(s, self->state.text_text, self->state.text_length); + } + + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, + self->state.text_opcode); + fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, + self->rdp_layer->mod->xrdp_bpp, + self->state.text_fgcolor, + self->rdp_layer->colormap.colors); + self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); + bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, + self->rdp_layer->mod->xrdp_bpp, + self->state.text_bgcolor, + self->rdp_layer->colormap.colors); + self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); + self->rdp_layer->mod->server_draw_text(self->rdp_layer->mod, + self->state.text_font, + self->state.text_flags, + self->state.text_mixmode, + self->state.text_clipleft, + self->state.text_cliptop, + self->state.text_clipright, + self->state.text_clipbottom, + self->state.text_boxleft, + self->state.text_boxtop, + self->state.text_boxright, + self->state.text_boxbottom, + self->state.text_x, + self->state.text_y, + self->state.text_text, + self->state.text_length); + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, 512); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 7); + out_uint8(rec_s, self->state.text_font); + out_uint8(rec_s, self->state.text_flags); + out_uint8(rec_s, self->state.text_opcode); + out_uint8(rec_s, self->state.text_mixmode); + out_uint32_le(rec_s, self->state.text_fgcolor); + out_uint32_le(rec_s, self->state.text_bgcolor); + out_uint16_le(rec_s, self->state.text_clipleft); + out_uint16_le(rec_s, self->state.text_cliptop); + out_uint16_le(rec_s, self->state.text_clipright); + out_uint16_le(rec_s, self->state.text_clipbottom); + out_uint16_le(rec_s, self->state.text_boxleft); + out_uint16_le(rec_s, self->state.text_boxtop); + out_uint16_le(rec_s, self->state.text_boxright); + out_uint16_le(rec_s, self->state.text_boxbottom); + out_uint16_le(rec_s, self->state.text_x); + out_uint16_le(rec_s, self->state.text_y); + out_uint16_le(rec_s, self->state.text_length); + out_uint8a(rec_s, self->state.text_text, self->state.text_length); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } } /*****************************************************************************/ /* Process a destination blt order */ static void APP_CC -rdp_orders_process_destblt(struct rdp_orders* self, struct stream* s, +rdp_orders_process_destblt(struct rdp_orders *self, struct stream *s, int present, int delta) { - struct stream* rec_s = (struct stream *)NULL; + struct stream *rec_s = (struct stream *)NULL; - if (present & 0x01) - { - rdp_orders_in_coord(s, &self->state.dest_x, delta); - } - if (present & 0x02) - { - rdp_orders_in_coord(s, &self->state.dest_y, delta); - } - if (present & 0x04) - { - rdp_orders_in_coord(s, &self->state.dest_cx, delta); - } - if (present & 0x08) - { - rdp_orders_in_coord(s, &self->state.dest_cy, delta); - } - if (present & 0x10) - { - in_uint8(s, self->state.dest_opcode); - } - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, - self->state.dest_opcode); - self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, - self->state.dest_x, - self->state.dest_y, - self->state.dest_cx, - self->state.dest_cy); - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); - if (self->rdp_layer->rec_mode) - { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, 512); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 6); - out_uint16_le(rec_s, self->state.dest_x); - out_uint16_le(rec_s, self->state.dest_y); - out_uint16_le(rec_s, self->state.dest_cx); - out_uint16_le(rec_s, self->state.dest_cy); - out_uint8(rec_s, self->state.dest_opcode); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } + if (present & 0x01) + { + rdp_orders_in_coord(s, &self->state.dest_x, delta); + } + + if (present & 0x02) + { + rdp_orders_in_coord(s, &self->state.dest_y, delta); + } + + if (present & 0x04) + { + rdp_orders_in_coord(s, &self->state.dest_cx, delta); + } + + if (present & 0x08) + { + rdp_orders_in_coord(s, &self->state.dest_cy, delta); + } + + if (present & 0x10) + { + in_uint8(s, self->state.dest_opcode); + } + + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, + self->state.dest_opcode); + self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, + self->state.dest_x, + self->state.dest_y, + self->state.dest_cx, + self->state.dest_cy); + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, 512); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 6); + out_uint16_le(rec_s, self->state.dest_x); + out_uint16_le(rec_s, self->state.dest_y); + out_uint16_le(rec_s, self->state.dest_cx); + out_uint16_le(rec_s, self->state.dest_cy); + out_uint8(rec_s, self->state.dest_opcode); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } } /*****************************************************************************/ /* Process a pattern blt order */ static void APP_CC -rdp_orders_process_patblt(struct rdp_orders* self, struct stream* s, +rdp_orders_process_patblt(struct rdp_orders *self, struct stream *s, int present, int delta) { - int fgcolor = 0; - int bgcolor = 0; - struct stream* rec_s = (struct stream *)NULL; + int fgcolor = 0; + int bgcolor = 0; + struct stream *rec_s = (struct stream *)NULL; - if (present & 0x0001) - { - rdp_orders_in_coord(s, &self->state.pat_x, delta); - } - if (present & 0x0002) - { - rdp_orders_in_coord(s, &self->state.pat_y, delta); - } - if (present & 0x0004) - { - rdp_orders_in_coord(s, &self->state.pat_cx, delta); - } - if (present & 0x0008) - { - rdp_orders_in_coord(s, &self->state.pat_cy, delta); - } - if (present & 0x0010) - { - in_uint8(s, self->state.pat_opcode); - } - if (present & 0x0020) - { - rdp_orders_in_color(s, &self->state.pat_bgcolor); - } - if (present & 0x0040) - { - rdp_orders_in_color(s, &self->state.pat_fgcolor); - } - rdp_orders_parse_brush(s, &self->state.pat_brush, present >> 7); - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, - self->state.pat_opcode); - self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 1); - fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, - self->rdp_layer->mod->xrdp_bpp, - self->state.pat_fgcolor, - self->rdp_layer->colormap.colors); - self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); - bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, - self->rdp_layer->mod->xrdp_bpp, - self->state.pat_bgcolor, - self->rdp_layer->colormap.colors); - self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); - self->rdp_layer->mod->server_set_brush(self->rdp_layer->mod, - self->state.pat_brush.xorigin, - self->state.pat_brush.yorigin, - self->state.pat_brush.style, - self->state.pat_brush.pattern); - self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, - self->state.pat_x, - self->state.pat_y, - self->state.pat_cx, - self->state.pat_cy); - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); - self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 0); - if (self->rdp_layer->rec_mode) - { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, 512); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 5); - out_uint16_le(rec_s, self->state.pat_x); - out_uint16_le(rec_s, self->state.pat_y); - out_uint16_le(rec_s, self->state.pat_cx); - out_uint16_le(rec_s, self->state.pat_cy); - out_uint8(rec_s, self->state.pat_opcode); - out_uint32_le(rec_s, self->state.pat_fgcolor); - out_uint32_le(rec_s, self->state.pat_bgcolor); - out_uint8(rec_s, self->state.pat_brush.xorigin); - out_uint8(rec_s, self->state.pat_brush.yorigin); - out_uint8(rec_s, self->state.pat_brush.style); - out_uint8a(rec_s, self->state.pat_brush.pattern, 8); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } + if (present & 0x0001) + { + rdp_orders_in_coord(s, &self->state.pat_x, delta); + } + + if (present & 0x0002) + { + rdp_orders_in_coord(s, &self->state.pat_y, delta); + } + + if (present & 0x0004) + { + rdp_orders_in_coord(s, &self->state.pat_cx, delta); + } + + if (present & 0x0008) + { + rdp_orders_in_coord(s, &self->state.pat_cy, delta); + } + + if (present & 0x0010) + { + in_uint8(s, self->state.pat_opcode); + } + + if (present & 0x0020) + { + rdp_orders_in_color(s, &self->state.pat_bgcolor); + } + + if (present & 0x0040) + { + rdp_orders_in_color(s, &self->state.pat_fgcolor); + } + + rdp_orders_parse_brush(s, &self->state.pat_brush, present >> 7); + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, + self->state.pat_opcode); + self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 1); + fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, + self->rdp_layer->mod->xrdp_bpp, + self->state.pat_fgcolor, + self->rdp_layer->colormap.colors); + self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); + bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, + self->rdp_layer->mod->xrdp_bpp, + self->state.pat_bgcolor, + self->rdp_layer->colormap.colors); + self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); + self->rdp_layer->mod->server_set_brush(self->rdp_layer->mod, + self->state.pat_brush.xorigin, + self->state.pat_brush.yorigin, + self->state.pat_brush.style, + self->state.pat_brush.pattern); + self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, + self->state.pat_x, + self->state.pat_y, + self->state.pat_cx, + self->state.pat_cy); + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); + self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 0); + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, 512); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 5); + out_uint16_le(rec_s, self->state.pat_x); + out_uint16_le(rec_s, self->state.pat_y); + out_uint16_le(rec_s, self->state.pat_cx); + out_uint16_le(rec_s, self->state.pat_cy); + out_uint8(rec_s, self->state.pat_opcode); + out_uint32_le(rec_s, self->state.pat_fgcolor); + out_uint32_le(rec_s, self->state.pat_bgcolor); + out_uint8(rec_s, self->state.pat_brush.xorigin); + out_uint8(rec_s, self->state.pat_brush.yorigin); + out_uint8(rec_s, self->state.pat_brush.style); + out_uint8a(rec_s, self->state.pat_brush.pattern, 8); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } } /*****************************************************************************/ /* Process a screen blt order */ static void APP_CC -rdp_orders_process_screenblt(struct rdp_orders* self, struct stream* s, +rdp_orders_process_screenblt(struct rdp_orders *self, struct stream *s, int present, int delta) { - struct stream* rec_s; + struct stream *rec_s; - if (present & 0x0001) - { - rdp_orders_in_coord(s, &self->state.screenblt_x, delta); - } - if (present & 0x0002) - { - rdp_orders_in_coord(s, &self->state.screenblt_y, delta); - } - if (present & 0x0004) - { - rdp_orders_in_coord(s, &self->state.screenblt_cx, delta); - } - if (present & 0x0008) - { - rdp_orders_in_coord(s, &self->state.screenblt_cy, delta); - } - if (present & 0x0010) - { - in_uint8(s, self->state.screenblt_opcode); - } - if (present & 0x0020) - { - rdp_orders_in_coord(s, &self->state.screenblt_srcx, delta); - } - if (present & 0x0040) - { - rdp_orders_in_coord(s, &self->state.screenblt_srcy, delta); - } - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, - self->state.screenblt_opcode); - self->rdp_layer->mod->server_screen_blt(self->rdp_layer->mod, - self->state.screenblt_x, - self->state.screenblt_y, - self->state.screenblt_cx, - self->state.screenblt_cy, - self->state.screenblt_srcx, - self->state.screenblt_srcy); - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); - if (self->rdp_layer->rec_mode) - { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, 512); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 4); - out_uint16_le(rec_s, self->state.screenblt_x); - out_uint16_le(rec_s, self->state.screenblt_y); - out_uint16_le(rec_s, self->state.screenblt_cx); - out_uint16_le(rec_s, self->state.screenblt_cy); - out_uint16_le(rec_s, self->state.screenblt_srcx); - out_uint16_le(rec_s, self->state.screenblt_srcy); - out_uint8(rec_s, self->state.screenblt_opcode); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } + if (present & 0x0001) + { + rdp_orders_in_coord(s, &self->state.screenblt_x, delta); + } + + if (present & 0x0002) + { + rdp_orders_in_coord(s, &self->state.screenblt_y, delta); + } + + if (present & 0x0004) + { + rdp_orders_in_coord(s, &self->state.screenblt_cx, delta); + } + + if (present & 0x0008) + { + rdp_orders_in_coord(s, &self->state.screenblt_cy, delta); + } + + if (present & 0x0010) + { + in_uint8(s, self->state.screenblt_opcode); + } + + if (present & 0x0020) + { + rdp_orders_in_coord(s, &self->state.screenblt_srcx, delta); + } + + if (present & 0x0040) + { + rdp_orders_in_coord(s, &self->state.screenblt_srcy, delta); + } + + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, + self->state.screenblt_opcode); + self->rdp_layer->mod->server_screen_blt(self->rdp_layer->mod, + self->state.screenblt_x, + self->state.screenblt_y, + self->state.screenblt_cx, + self->state.screenblt_cy, + self->state.screenblt_srcx, + self->state.screenblt_srcy); + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, 512); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 4); + out_uint16_le(rec_s, self->state.screenblt_x); + out_uint16_le(rec_s, self->state.screenblt_y); + out_uint16_le(rec_s, self->state.screenblt_cx); + out_uint16_le(rec_s, self->state.screenblt_cy); + out_uint16_le(rec_s, self->state.screenblt_srcx); + out_uint16_le(rec_s, self->state.screenblt_srcy); + out_uint8(rec_s, self->state.screenblt_opcode); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } } /*****************************************************************************/ /* Process a line order */ static void APP_CC -rdp_orders_process_line(struct rdp_orders* self, struct stream* s, +rdp_orders_process_line(struct rdp_orders *self, struct stream *s, int present, int delta) { - int bgcolor = 0; - int fgcolor = 0; - struct stream* rec_s = (struct stream *)NULL; + int bgcolor = 0; + int fgcolor = 0; + struct stream *rec_s = (struct stream *)NULL; - if (present & 0x0001) - { - in_uint16_le(s, self->state.line_mixmode); - } - if (present & 0x0002) - { - rdp_orders_in_coord(s, &self->state.line_startx, delta); - } - if (present & 0x0004) - { - rdp_orders_in_coord(s, &self->state.line_starty, delta); - } - if (present & 0x0008) - { - rdp_orders_in_coord(s, &self->state.line_endx, delta); - } - if (present & 0x0010) - { - rdp_orders_in_coord(s, &self->state.line_endy, delta); - } - if (present & 0x0020) - { - rdp_orders_in_color(s, &self->state.line_bgcolor); - } - if (present & 0x0040) - { - in_uint8(s, self->state.line_opcode); - } - rdp_orders_parse_pen(s, &self->state.line_pen, present >> 7); - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, - self->state.line_opcode); - bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, - self->rdp_layer->mod->xrdp_bpp, - self->state.line_bgcolor, - self->rdp_layer->colormap.colors); - fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, - self->rdp_layer->mod->xrdp_bpp, - self->state.line_pen.color, - self->rdp_layer->colormap.colors); - self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); - self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); - self->rdp_layer->mod->server_set_pen(self->rdp_layer->mod, - self->state.line_pen.style, - self->state.line_pen.width); - self->rdp_layer->mod->server_draw_line(self->rdp_layer->mod, - self->state.line_startx, - self->state.line_starty, - self->state.line_endx, - self->state.line_endy); - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); - if (self->rdp_layer->rec_mode) - { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, 512); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 3); - out_uint16_le(rec_s, self->state.line_mixmode); - out_uint16_le(rec_s, self->state.line_startx); - out_uint16_le(rec_s, self->state.line_starty); - out_uint16_le(rec_s, self->state.line_endx); - out_uint16_le(rec_s, self->state.line_endy); - out_uint32_le(rec_s, self->state.line_bgcolor); - out_uint8(rec_s, self->state.line_opcode); - out_uint8(rec_s, self->state.line_pen.style); - out_uint8(rec_s, self->state.line_pen.width); - out_uint32_le(rec_s, self->state.line_pen.color); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } + if (present & 0x0001) + { + in_uint16_le(s, self->state.line_mixmode); + } + + if (present & 0x0002) + { + rdp_orders_in_coord(s, &self->state.line_startx, delta); + } + + if (present & 0x0004) + { + rdp_orders_in_coord(s, &self->state.line_starty, delta); + } + + if (present & 0x0008) + { + rdp_orders_in_coord(s, &self->state.line_endx, delta); + } + + if (present & 0x0010) + { + rdp_orders_in_coord(s, &self->state.line_endy, delta); + } + + if (present & 0x0020) + { + rdp_orders_in_color(s, &self->state.line_bgcolor); + } + + if (present & 0x0040) + { + in_uint8(s, self->state.line_opcode); + } + + rdp_orders_parse_pen(s, &self->state.line_pen, present >> 7); + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, + self->state.line_opcode); + bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, + self->rdp_layer->mod->xrdp_bpp, + self->state.line_bgcolor, + self->rdp_layer->colormap.colors); + fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, + self->rdp_layer->mod->xrdp_bpp, + self->state.line_pen.color, + self->rdp_layer->colormap.colors); + self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); + self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); + self->rdp_layer->mod->server_set_pen(self->rdp_layer->mod, + self->state.line_pen.style, + self->state.line_pen.width); + self->rdp_layer->mod->server_draw_line(self->rdp_layer->mod, + self->state.line_startx, + self->state.line_starty, + self->state.line_endx, + self->state.line_endy); + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, 512); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 3); + out_uint16_le(rec_s, self->state.line_mixmode); + out_uint16_le(rec_s, self->state.line_startx); + out_uint16_le(rec_s, self->state.line_starty); + out_uint16_le(rec_s, self->state.line_endx); + out_uint16_le(rec_s, self->state.line_endy); + out_uint32_le(rec_s, self->state.line_bgcolor); + out_uint8(rec_s, self->state.line_opcode); + out_uint8(rec_s, self->state.line_pen.style); + out_uint8(rec_s, self->state.line_pen.width); + out_uint32_le(rec_s, self->state.line_pen.color); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } } /*****************************************************************************/ /* Process an opaque rectangle order */ static void APP_CC -rdp_orders_process_rect(struct rdp_orders* self, struct stream* s, +rdp_orders_process_rect(struct rdp_orders *self, struct stream *s, int present, int delta) { - int i = 0; - int fgcolor = 0; - struct stream* rec_s = (struct stream *)NULL; + int i = 0; + int fgcolor = 0; + struct stream *rec_s = (struct stream *)NULL; - if (present & 0x01) - { - rdp_orders_in_coord(s, &self->state.rect_x, delta); - } - if (present & 0x02) - { - rdp_orders_in_coord(s, &self->state.rect_y, delta); - } - if (present & 0x04) - { - rdp_orders_in_coord(s, &self->state.rect_cx, delta); - } - if (present & 0x08) - { - rdp_orders_in_coord(s, &self->state.rect_cy, delta); - } - if (present & 0x10) - { - in_uint8(s, i); - self->state.rect_color = (self->state.rect_color & 0xffffff00) | i; - } - if (present & 0x20) - { - in_uint8(s, i); - self->state.rect_color = (self->state.rect_color & 0xffff00ff) | (i << 8); - } - if (present & 0x40) - { - in_uint8(s, i); - self->state.rect_color = (self->state.rect_color & 0xff00ffff) | (i << 16); - } - fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, - self->rdp_layer->mod->xrdp_bpp, - self->state.rect_color, - self->rdp_layer->colormap.colors); - self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); - self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, - self->state.rect_x, - self->state.rect_y, - self->state.rect_cx, - self->state.rect_cy); - if (self->rdp_layer->rec_mode) - { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, 512); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 1); - out_uint16_le(rec_s, self->state.rect_x); - out_uint16_le(rec_s, self->state.rect_y); - out_uint16_le(rec_s, self->state.rect_cx); - out_uint16_le(rec_s, self->state.rect_cy); - out_uint32_le(rec_s, self->state.rect_color); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); - } + if (present & 0x01) + { + rdp_orders_in_coord(s, &self->state.rect_x, delta); + } + + if (present & 0x02) + { + rdp_orders_in_coord(s, &self->state.rect_y, delta); + } + + if (present & 0x04) + { + rdp_orders_in_coord(s, &self->state.rect_cx, delta); + } + + if (present & 0x08) + { + rdp_orders_in_coord(s, &self->state.rect_cy, delta); + } + + if (present & 0x10) + { + in_uint8(s, i); + self->state.rect_color = (self->state.rect_color & 0xffffff00) | i; + } + + if (present & 0x20) + { + in_uint8(s, i); + self->state.rect_color = (self->state.rect_color & 0xffff00ff) | (i << 8); + } + + if (present & 0x40) + { + in_uint8(s, i); + self->state.rect_color = (self->state.rect_color & 0xff00ffff) | (i << 16); + } + + fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, + self->rdp_layer->mod->xrdp_bpp, + self->state.rect_color, + self->rdp_layer->colormap.colors); + self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); + self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, + self->state.rect_x, + self->state.rect_y, + self->state.rect_cx, + self->state.rect_cy); + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, 512); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 1); + out_uint16_le(rec_s, self->state.rect_x); + out_uint16_le(rec_s, self->state.rect_y); + out_uint16_le(rec_s, self->state.rect_cx); + out_uint16_le(rec_s, self->state.rect_cy); + out_uint32_le(rec_s, self->state.rect_color); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } } /*****************************************************************************/ /* Process a desktop save order */ static void APP_CC -rdp_orders_process_desksave(struct rdp_orders* self, struct stream* s, +rdp_orders_process_desksave(struct rdp_orders *self, struct stream *s, int present, int delta) { - int width = 0; - int height = 0; + int width = 0; + int height = 0; - if (present & 0x01) - { - in_uint32_le(s, self->state.desksave_offset); - } - if (present & 0x02) - { - rdp_orders_in_coord(s, &self->state.desksave_left, delta); - } - if (present & 0x04) - { - rdp_orders_in_coord(s, &self->state.desksave_top, delta); - } - if (present & 0x08) - { - rdp_orders_in_coord(s, &self->state.desksave_right, delta); - } - if (present & 0x10) - { - rdp_orders_in_coord(s, &self->state.desksave_bottom, delta); - } - if (present & 0x20) - { - in_uint8(s, self->state.desksave_action); - } -// width = (self->state.desksave_right - self->state.desksave_left) + 1; -// height = (self->state.desksave_bottom - self->state.desksave_top) + 1; - if (self->state.desksave_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); - } + if (present & 0x01) + { + in_uint32_le(s, self->state.desksave_offset); + } + + if (present & 0x02) + { + rdp_orders_in_coord(s, &self->state.desksave_left, delta); + } + + if (present & 0x04) + { + rdp_orders_in_coord(s, &self->state.desksave_top, delta); + } + + if (present & 0x08) + { + rdp_orders_in_coord(s, &self->state.desksave_right, delta); + } + + if (present & 0x10) + { + rdp_orders_in_coord(s, &self->state.desksave_bottom, delta); + } + + if (present & 0x20) + { + in_uint8(s, self->state.desksave_action); + } + + // width = (self->state.desksave_right - self->state.desksave_left) + 1; + // height = (self->state.desksave_bottom - self->state.desksave_top) + 1; + if (self->state.desksave_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 APP_CC -rdp_orders_process_memblt(struct rdp_orders* self, struct stream* s, +rdp_orders_process_memblt(struct rdp_orders *self, struct stream *s, int present, int delta) { - struct rdp_bitmap* bitmap = (struct rdp_bitmap *)NULL; - struct stream* rec_s = (struct stream *)NULL; - char* bmpdata = (char *)NULL; + struct rdp_bitmap *bitmap = (struct rdp_bitmap *)NULL; + struct stream *rec_s = (struct stream *)NULL; + char *bmpdata = (char *)NULL; - if (present & 0x0001) - { - in_uint8(s, self->state.memblt_cache_id); - in_uint8(s, self->state.memblt_color_table); - } - if (present & 0x0002) - { - rdp_orders_in_coord(s, &self->state.memblt_x, delta); - } - if (present & 0x0004) - { - rdp_orders_in_coord(s, &self->state.memblt_y, delta); - } - if (present & 0x0008) - { - rdp_orders_in_coord(s, &self->state.memblt_cx, delta); - } - if (present & 0x0010) - { - rdp_orders_in_coord(s, &self->state.memblt_cy, delta); - } - if (present & 0x0020) - { - in_uint8(s, self->state.memblt_opcode); - } - if (present & 0x0040) - { - rdp_orders_in_coord(s, &self->state.memblt_srcx, delta); - } - if (present & 0x0080) - { - rdp_orders_in_coord(s, &self->state.memblt_srcy, delta); - } - if (present & 0x0100) - { - in_uint16_le(s, self->state.memblt_cache_idx); - } - bitmap = self->cache_bitmap[self->state.memblt_cache_id] - [self->state.memblt_cache_idx]; - if (bitmap != 0) - { - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, - self->state.memblt_opcode); - bmpdata = rdp_orders_convert_bitmap(self->rdp_layer->mod->rdp_bpp, - self->rdp_layer->mod->xrdp_bpp, - bitmap->data, bitmap->width, - bitmap->height, - self->cache_colormap - [self->state.memblt_color_table]->colors); - self->rdp_layer->mod->server_paint_rect(self->rdp_layer->mod, - self->state.memblt_x, - self->state.memblt_y, - self->state.memblt_cx, - self->state.memblt_cy, - bmpdata, - bitmap->width, + if (present & 0x0001) + { + in_uint8(s, self->state.memblt_cache_id); + in_uint8(s, self->state.memblt_color_table); + } + + if (present & 0x0002) + { + rdp_orders_in_coord(s, &self->state.memblt_x, delta); + } + + if (present & 0x0004) + { + rdp_orders_in_coord(s, &self->state.memblt_y, delta); + } + + if (present & 0x0008) + { + rdp_orders_in_coord(s, &self->state.memblt_cx, delta); + } + + if (present & 0x0010) + { + rdp_orders_in_coord(s, &self->state.memblt_cy, delta); + } + + if (present & 0x0020) + { + in_uint8(s, self->state.memblt_opcode); + } + + if (present & 0x0040) + { + rdp_orders_in_coord(s, &self->state.memblt_srcx, delta); + } + + if (present & 0x0080) + { + rdp_orders_in_coord(s, &self->state.memblt_srcy, delta); + } + + if (present & 0x0100) + { + in_uint16_le(s, self->state.memblt_cache_idx); + } + + bitmap = self->cache_bitmap[self->state.memblt_cache_id] + [self->state.memblt_cache_idx]; + + if (bitmap != 0) + { + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, + self->state.memblt_opcode); + bmpdata = rdp_orders_convert_bitmap(self->rdp_layer->mod->rdp_bpp, + self->rdp_layer->mod->xrdp_bpp, + bitmap->data, bitmap->width, bitmap->height, - self->state.memblt_srcx, - self->state.memblt_srcy); - self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); - if (self->rdp_layer->rec_mode) - { - rdp_rec_check_file(self->rdp_layer); - make_stream(rec_s); - init_stream(rec_s, 512); - s_push_layer(rec_s, iso_hdr, 4); - out_uint8(rec_s, 2); - out_uint8(rec_s, self->state.memblt_opcode); - out_uint16_le(rec_s, self->state.memblt_x); - out_uint16_le(rec_s, self->state.memblt_y); - out_uint16_le(rec_s, self->state.memblt_cx); - out_uint16_le(rec_s, self->state.memblt_cy); - out_uint16_le(rec_s, self->state.memblt_cache_id); - out_uint16_le(rec_s, self->state.memblt_cache_idx); - out_uint16_le(rec_s, self->state.memblt_srcx); - out_uint16_le(rec_s, self->state.memblt_srcy); - rdp_rec_write_item(self->rdp_layer, rec_s); - free_stream(rec_s); + self->cache_colormap + [self->state.memblt_color_table]->colors); + self->rdp_layer->mod->server_paint_rect(self->rdp_layer->mod, + self->state.memblt_x, + self->state.memblt_y, + self->state.memblt_cx, + self->state.memblt_cy, + bmpdata, + bitmap->width, + bitmap->height, + self->state.memblt_srcx, + self->state.memblt_srcy); + self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); + + if (self->rdp_layer->rec_mode) + { + rdp_rec_check_file(self->rdp_layer); + make_stream(rec_s); + init_stream(rec_s, 512); + s_push_layer(rec_s, iso_hdr, 4); + out_uint8(rec_s, 2); + out_uint8(rec_s, self->state.memblt_opcode); + out_uint16_le(rec_s, self->state.memblt_x); + out_uint16_le(rec_s, self->state.memblt_y); + out_uint16_le(rec_s, self->state.memblt_cx); + out_uint16_le(rec_s, self->state.memblt_cy); + out_uint16_le(rec_s, self->state.memblt_cache_id); + out_uint16_le(rec_s, self->state.memblt_cache_idx); + out_uint16_le(rec_s, self->state.memblt_srcx); + out_uint16_le(rec_s, self->state.memblt_srcy); + rdp_rec_write_item(self->rdp_layer, rec_s); + free_stream(rec_s); + } + + if (bmpdata != bitmap->data) + { + g_free(bmpdata); + } } - if (bmpdata != bitmap->data) - { - g_free(bmpdata); - } - } } /*****************************************************************************/ /* Process a 3-way blt order */ static void APP_CC -rdp_orders_process_triblt(struct rdp_orders* self, struct stream* s, +rdp_orders_process_triblt(struct rdp_orders *self, struct stream *s, int present, int delta) { - /* not used */ + /* not used */ } /*****************************************************************************/ /* Process a polyline order */ static void APP_CC -rdp_orders_process_polyline(struct rdp_orders* self, struct stream* s, +rdp_orders_process_polyline(struct rdp_orders *self, struct stream *s, int present, int delta) { - if (present & 0x01) - { - rdp_orders_in_coord(s, &self->state.polyline_x, delta); - } - if (present & 0x02) - { - rdp_orders_in_coord(s, &self->state.polyline_y, delta); - } - if (present & 0x04) - { - in_uint8(s, self->state.polyline_opcode); - } - if (present & 0x10) - { - rdp_orders_in_color(s, &self->state.polyline_fgcolor); - } - if (present & 0x20) - { - in_uint8(s, self->state.polyline_lines); - } - if (present & 0x40) - { - in_uint8(s, self->state.polyline_datasize); - in_uint8a(s, self->state.polyline_data, self->state.polyline_datasize); - } - /* todo */ + if (present & 0x01) + { + rdp_orders_in_coord(s, &self->state.polyline_x, delta); + } + + if (present & 0x02) + { + rdp_orders_in_coord(s, &self->state.polyline_y, delta); + } + + if (present & 0x04) + { + in_uint8(s, self->state.polyline_opcode); + } + + if (present & 0x10) + { + rdp_orders_in_color(s, &self->state.polyline_fgcolor); + } + + if (present & 0x20) + { + in_uint8(s, self->state.polyline_lines); + } + + if (present & 0x40) + { + in_uint8(s, self->state.polyline_datasize); + in_uint8a(s, self->state.polyline_data, self->state.polyline_datasize); + } + + /* todo */ } /*****************************************************************************/ int APP_CC -rdp_orders_process_orders(struct rdp_orders* self, struct stream* s, +rdp_orders_process_orders(struct rdp_orders *self, struct stream *s, int num_orders) { - int processed = 0; - int order_flags = 0; - int size = 0; - int present = 0; - int delta = 0; + int processed = 0; + int order_flags = 0; + int size = 0; + int present = 0; + int delta = 0; - processed = 0; - while (processed < num_orders) - { - in_uint8(s, order_flags); - if (!(order_flags & RDP_ORDER_STANDARD)) + processed = 0; + + while (processed < num_orders) { - /* error, this should always be set */ - break; - } - if (order_flags & RDP_ORDER_SECONDARY) - { - rdp_orders_process_secondary_order(self, s); - } - else - { - if (order_flags & RDP_ORDER_CHANGE) - { - in_uint8(s, self->state.order_type); - } - switch (self->state.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: - size = 2; - break; - default: - size = 1; - break; - } - rdp_orders_in_present(s, &present, order_flags, size); - if (order_flags & RDP_ORDER_BOUNDS) - { - if (!(order_flags & RDP_ORDER_LASTBOUNDS)) + in_uint8(s, order_flags); + + if (!(order_flags & RDP_ORDER_STANDARD)) { - rdp_orders_parse_bounds(self, s); + /* error, this should always be set */ + break; } - self->rdp_layer->mod->server_set_clip(self->rdp_layer->mod, - self->state.clip_left, - self->state.clip_top, - (self->state.clip_right - self->state.clip_left) + 1, - (self->state.clip_bottom - self->state.clip_top) + 1); - } - delta = order_flags & RDP_ORDER_DELTA; - switch (self->state.order_type) - { - case RDP_ORDER_TEXT2: - rdp_orders_process_text2(self, s, present, delta); - break; - case RDP_ORDER_DESTBLT: - rdp_orders_process_destblt(self, s, present, delta); - break; - case RDP_ORDER_PATBLT: - rdp_orders_process_patblt(self, s, present, delta); - break; - case RDP_ORDER_SCREENBLT: - rdp_orders_process_screenblt(self, s, present, delta); - break; - case RDP_ORDER_LINE: - rdp_orders_process_line(self, s, present, delta); - break; - case RDP_ORDER_RECT: - rdp_orders_process_rect(self, s, present, delta); - break; - case RDP_ORDER_DESKSAVE: - rdp_orders_process_desksave(self, s, present, delta); - break; - case RDP_ORDER_MEMBLT: - rdp_orders_process_memblt(self, s, present, delta); - break; - case RDP_ORDER_TRIBLT: - rdp_orders_process_triblt(self, s, present, delta); - break; - case RDP_ORDER_POLYLINE: - rdp_orders_process_polyline(self, s, present, delta); - break; - default: - /* error unknown order */ - break; - } - if (order_flags & RDP_ORDER_BOUNDS) - { - self->rdp_layer->mod->server_reset_clip(self->rdp_layer->mod); - } + + if (order_flags & RDP_ORDER_SECONDARY) + { + rdp_orders_process_secondary_order(self, s); + } + else + { + if (order_flags & RDP_ORDER_CHANGE) + { + in_uint8(s, self->state.order_type); + } + + switch (self->state.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: + size = 2; + break; + default: + size = 1; + break; + } + + rdp_orders_in_present(s, &present, order_flags, size); + + if (order_flags & RDP_ORDER_BOUNDS) + { + if (!(order_flags & RDP_ORDER_LASTBOUNDS)) + { + rdp_orders_parse_bounds(self, s); + } + + self->rdp_layer->mod->server_set_clip(self->rdp_layer->mod, + self->state.clip_left, + self->state.clip_top, + (self->state.clip_right - self->state.clip_left) + 1, + (self->state.clip_bottom - self->state.clip_top) + 1); + } + + delta = order_flags & RDP_ORDER_DELTA; + + switch (self->state.order_type) + { + case RDP_ORDER_TEXT2: + rdp_orders_process_text2(self, s, present, delta); + break; + case RDP_ORDER_DESTBLT: + rdp_orders_process_destblt(self, s, present, delta); + break; + case RDP_ORDER_PATBLT: + rdp_orders_process_patblt(self, s, present, delta); + break; + case RDP_ORDER_SCREENBLT: + rdp_orders_process_screenblt(self, s, present, delta); + break; + case RDP_ORDER_LINE: + rdp_orders_process_line(self, s, present, delta); + break; + case RDP_ORDER_RECT: + rdp_orders_process_rect(self, s, present, delta); + break; + case RDP_ORDER_DESKSAVE: + rdp_orders_process_desksave(self, s, present, delta); + break; + case RDP_ORDER_MEMBLT: + rdp_orders_process_memblt(self, s, present, delta); + break; + case RDP_ORDER_TRIBLT: + rdp_orders_process_triblt(self, s, present, delta); + break; + case RDP_ORDER_POLYLINE: + rdp_orders_process_polyline(self, s, present, delta); + break; + default: + /* error unknown order */ + break; + } + + if (order_flags & RDP_ORDER_BOUNDS) + { + self->rdp_layer->mod->server_reset_clip(self->rdp_layer->mod); + } + } + + processed++; } - processed++; - } - return 0; + + return 0; } /*****************************************************************************/ /* returns pointer, it might return bmpdata if the data dosen't need to be converted, else it mallocs it. The calling function must free it if needed */ -char* APP_CC -rdp_orders_convert_bitmap(int in_bpp, int out_bpp, char* bmpdata, - int width, int height, int* palette) +char *APP_CC +rdp_orders_convert_bitmap(int in_bpp, int out_bpp, char *bmpdata, + int width, int height, int *palette) { - char* out = (char *)NULL; - char* src = (char *)NULL; - char* dst = (char *)NULL; - int i = 0; - int j = 0; - int red = 0; - int green = 0; - int blue = 0; - int pixel = 0; + char *out = (char *)NULL; + char *src = (char *)NULL; + char *dst = (char *)NULL; + int i = 0; + int j = 0; + int red = 0; + int green = 0; + int blue = 0; + int pixel = 0; - if ((in_bpp == 8) && (out_bpp == 8)) - { - out = (char*)g_malloc(width * height, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + if ((in_bpp == 8) && (out_bpp == 8)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - *dst = pixel; - src++; - dst++; - } + out = (char *)g_malloc(width * height, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + *dst = pixel; + src++; + dst++; + } + } + + return out; } - return out; - } - if ((in_bpp == 8) && (out_bpp == 16)) - { - out = (char*)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 8) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16*)dst) = pixel; - src++; - dst += 2; - } + out = (char *)g_malloc(width * height * 2, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *((tui16 *)dst) = pixel; + src++; + dst += 2; + } + } + + return out; } - return out; - } - if ((in_bpp == 8) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 8) && (out_bpp == 24)) { - for (j = 0; j < width; j++) - { - pixel = *((tui8*)src); - pixel = palette[pixel]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src++; - dst += 4; - } + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui8 *)src); + pixel = palette[pixel]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src++; + dst += 4; + } + } + + return out; } - return out; - } - if ((in_bpp == 15) && (out_bpp == 16)) - { - out = (char*)g_malloc(width * height * 2, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 15) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *((tui16*)dst) = pixel; - src += 2; - dst += 2; - } + out = (char *)g_malloc(width * height * 2, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *((tui16 *)dst) = pixel; + src += 2; + dst += 2; + } + } + + return out; } - return out; - } - if ((in_bpp == 15) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 15) && (out_bpp == 24)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src += 2; - dst += 4; - } + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src += 2; + dst += 4; + } + } + + return out; } - return out; - } - if ((in_bpp == 16) && (out_bpp == 16)) - { - return bmpdata; - } - if ((in_bpp == 16) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 16) && (out_bpp == 16)) { - for (j = 0; j < width; j++) - { - pixel = *((tui16*)src); - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - src += 2; - dst += 4; - } + return bmpdata; } - return out; - } - if ((in_bpp == 24) && (out_bpp == 24)) - { - out = (char*)g_malloc(width * height * 4, 0); - src = bmpdata; - dst = out; - for (i = 0; i < height; i++) + + if ((in_bpp == 16) && (out_bpp == 24)) { - for (j = 0; j < width; j++) - { - blue = *((tui8*)src); - src++; - green = *((tui8*)src); - src++; - red = *((tui8*)src); - src++; - pixel = COLOR24RGB(red, green, blue); - *((tui32*)dst) = pixel; - dst += 4; - } + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + pixel = *((tui16 *)src); + SPLITCOLOR16(red, green, blue, pixel); + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + src += 2; + dst += 4; + } + } + + return out; } - return out; - } - return 0; + + if ((in_bpp == 24) && (out_bpp == 24)) + { + out = (char *)g_malloc(width * height * 4, 0); + src = bmpdata; + dst = out; + + for (i = 0; i < height; i++) + { + for (j = 0; j < width; j++) + { + blue = *((tui8 *)src); + src++; + green = *((tui8 *)src); + src++; + red = *((tui8 *)src); + src++; + pixel = COLOR24RGB(red, green, blue); + *((tui32 *)dst) = pixel; + dst += 4; + } + } + + return out; + } + + return 0; } /*****************************************************************************/ /* returns color or 0 */ int APP_CC -rdp_orders_convert_color(int in_bpp, int out_bpp, int in_color, int* palette) +rdp_orders_convert_color(int in_bpp, int out_bpp, int in_color, int *palette) { - int pixel = 0; - int red = 0; - int green = 0; - int blue = 0; + int pixel = 0; + int red = 0; + int green = 0; + int blue = 0; - if ((in_bpp == 8) && (out_bpp == 8)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - return pixel; - } - if ((in_bpp == 8) && (out_bpp == 16)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - if ((in_bpp == 8) && (out_bpp == 24)) - { - pixel = palette[in_color]; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 15) && (out_bpp == 16)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - return pixel; - } - if ((in_bpp == 15) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR15(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 16) && (out_bpp == 16)) - { - return in_color; - } - if ((in_bpp == 16) && (out_bpp == 24)) - { - pixel = in_color; - SPLITCOLOR16(red, green, blue, pixel); - pixel = COLOR24BGR(red, green, blue); - return pixel; - } - if ((in_bpp == 24) && (out_bpp == 24)) - { - return in_color; - } - return 0; + if ((in_bpp == 8) && (out_bpp == 8)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 16)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + return pixel; + } + + if ((in_bpp == 8) && (out_bpp == 24)) + { + pixel = palette[in_color]; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 16)) + { + pixel = in_color; + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + return pixel; + } + + if ((in_bpp == 15) && (out_bpp == 24)) + { + pixel = in_color; + SPLITCOLOR15(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 16) && (out_bpp == 16)) + { + return in_color; + } + + if ((in_bpp == 16) && (out_bpp == 24)) + { + pixel = in_color; + SPLITCOLOR16(red, green, blue, pixel); + pixel = COLOR24BGR(red, green, blue); + return pixel; + } + + if ((in_bpp == 24) && (out_bpp == 24)) + { + return in_color; + } + + return 0; } diff --git a/rdp/rdp_rdp.c b/rdp/rdp_rdp.c index b3c6d42a..c42d6e5f 100644 --- a/rdp/rdp_rdp.c +++ b/rdp/rdp_rdp.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp rdp layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * librdp rdp layer + */ #include "rdp.h" @@ -27,321 +25,332 @@ #endif /*****************************************************************************/ -struct rdp_rdp* APP_CC -rdp_rdp_create(struct mod* owner) +struct rdp_rdp *APP_CC +rdp_rdp_create(struct mod *owner) { - struct rdp_rdp* self; + struct rdp_rdp *self; - self = (struct rdp_rdp*)g_malloc(sizeof(struct rdp_rdp), 1); - self->mod = owner; - self->sec_layer = rdp_sec_create(self); - self->bitmap_compression = 1; - self->bitmap_cache = 1; - self->desktop_save = 0; - self->orders = rdp_orders_create(self); - self->rec_mode = 0; - return self; + self = (struct rdp_rdp *)g_malloc(sizeof(struct rdp_rdp), 1); + self->mod = owner; + self->sec_layer = rdp_sec_create(self); + self->bitmap_compression = 1; + self->bitmap_cache = 1; + self->desktop_save = 0; + self->orders = rdp_orders_create(self); + self->rec_mode = 0; + return self; } /*****************************************************************************/ void APP_CC -rdp_rdp_delete(struct rdp_rdp* self) +rdp_rdp_delete(struct rdp_rdp *self) { - if (self == 0) - { - return; - } - rdp_orders_delete(self->orders); - rdp_sec_delete(self->sec_layer); - if (self->rec_fd != 0) - { - g_file_close(self->rec_fd); - self->rec_fd = 0; - } - g_free(self); + if (self == 0) + { + return; + } + + rdp_orders_delete(self->orders); + rdp_sec_delete(self->sec_layer); + + if (self->rec_fd != 0) + { + g_file_close(self->rec_fd); + self->rec_fd = 0; + } + + g_free(self); } /******************************************************************************/ /* Initialise an RDP packet */ int APP_CC -rdp_rdp_init(struct rdp_rdp* self, struct stream* s) +rdp_rdp_init(struct rdp_rdp *self, struct stream *s) { - if (rdp_sec_init(self->sec_layer, s, SEC_ENCRYPT) != 0) - { - return 1; - } - s_push_layer(s, rdp_hdr, 6); - return 0; + if (rdp_sec_init(self->sec_layer, s, SEC_ENCRYPT) != 0) + { + return 1; + } + + s_push_layer(s, rdp_hdr, 6); + return 0; } /******************************************************************************/ /* Send an RDP packet */ int APP_CC -rdp_rdp_send(struct rdp_rdp* self, struct stream* s, int pdu_type) +rdp_rdp_send(struct rdp_rdp *self, struct stream *s, int pdu_type) { - int len; - int sec_flags; + int len; + int sec_flags; - s_pop_layer(s, rdp_hdr); - len = s->end - s->p; - out_uint16_le(s, len); - out_uint16_le(s, pdu_type | 0x10); - out_uint16_le(s, self->sec_layer->mcs_layer->userid); - sec_flags = SEC_ENCRYPT; - if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) - { - return 1; - } - return 0; + s_pop_layer(s, rdp_hdr); + len = s->end - s->p; + out_uint16_le(s, len); + out_uint16_le(s, pdu_type | 0x10); + out_uint16_le(s, self->sec_layer->mcs_layer->userid); + sec_flags = SEC_ENCRYPT; + + if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) + { + return 1; + } + + return 0; } /******************************************************************************/ /* Initialise an RDP data packet */ int APP_CC -rdp_rdp_init_data(struct rdp_rdp* self, struct stream* s) +rdp_rdp_init_data(struct rdp_rdp *self, struct stream *s) { - if (rdp_sec_init(self->sec_layer, s, SEC_ENCRYPT) != 0) - { - return 1; - } - s_push_layer(s, rdp_hdr, 18); - return 0; + if (rdp_sec_init(self->sec_layer, s, SEC_ENCRYPT) != 0) + { + return 1; + } + + s_push_layer(s, rdp_hdr, 18); + return 0; } /******************************************************************************/ /* Send an RDP data packet */ int APP_CC -rdp_rdp_send_data(struct rdp_rdp* self, struct stream* s, int pdu_data_type) +rdp_rdp_send_data(struct rdp_rdp *self, struct stream *s, int pdu_data_type) { - int len; - int sec_flags; + int len; + int sec_flags; - s_pop_layer(s, rdp_hdr); - len = s->end - s->p; - out_uint16_le(s, len); - out_uint16_le(s, RDP_PDU_DATA | 0x10); - out_uint16_le(s, self->sec_layer->mcs_layer->userid); - out_uint32_le(s, self->share_id); - out_uint8(s, 0); - out_uint8(s, 1); - out_uint16_le(s, len - 14); - out_uint8(s, pdu_data_type); - out_uint8(s, 0); /* compress type */ - out_uint16_le(s, 0); /* compress len */ - sec_flags = SEC_ENCRYPT; - if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) - { - return 1; - } - return 0; + s_pop_layer(s, rdp_hdr); + len = s->end - s->p; + out_uint16_le(s, len); + out_uint16_le(s, RDP_PDU_DATA | 0x10); + out_uint16_le(s, self->sec_layer->mcs_layer->userid); + out_uint32_le(s, self->share_id); + out_uint8(s, 0); + out_uint8(s, 1); + out_uint16_le(s, len - 14); + out_uint8(s, pdu_data_type); + out_uint8(s, 0); /* compress type */ + out_uint16_le(s, 0); /* compress len */ + sec_flags = SEC_ENCRYPT; + + if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) + { + return 1; + } + + return 0; } /******************************************************************************/ /* Output general capability set */ static int APP_CC -rdp_rdp_out_general_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_general_caps(struct rdp_rdp *self, struct 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_le(s, 0); /* Pad */ - out_uint16_le(s, 0); /* Compression types */ - out_uint16_le(s, self->use_rdp5 ? 0x40d : 0); - out_uint16_le(s, 0); /* Update capability */ - out_uint16_le(s, 0); /* Remote unshare capability */ - out_uint16_le(s, 0); /* Compression level */ - out_uint16_le(s, 0); /* Pad */ - return 0; + 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_le(s, 0); /* Pad */ + out_uint16_le(s, 0); /* Compression types */ + out_uint16_le(s, self->use_rdp5 ? 0x40d : 0); + out_uint16_le(s, 0); /* Update capability */ + out_uint16_le(s, 0); /* Remote unshare capability */ + out_uint16_le(s, 0); /* Compression level */ + out_uint16_le(s, 0); /* Pad */ + return 0; } /******************************************************************************/ /* Output bitmap capability set */ static int APP_CC -rdp_rdp_out_bitmap_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_bitmap_caps(struct rdp_rdp *self, struct stream *s) { - out_uint16_le(s, RDP_CAPSET_BITMAP); - out_uint16_le(s, RDP_CAPLEN_BITMAP); - out_uint16_le(s, self->mod->rdp_bpp); /* Preferred BPP */ - 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_le(s, 0); /* Pad */ - out_uint16_le(s, 1); /* Allow resize */ - out_uint16_le(s, self->bitmap_compression); /* Support compression */ - out_uint16_le(s, 0); /* Unknown */ - out_uint16_le(s, 1); /* Unknown */ - out_uint16_le(s, 0); /* Pad */ - return 0; + out_uint16_le(s, RDP_CAPSET_BITMAP); + out_uint16_le(s, RDP_CAPLEN_BITMAP); + out_uint16_le(s, self->mod->rdp_bpp); /* Preferred BPP */ + 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_le(s, 0); /* Pad */ + out_uint16_le(s, 1); /* Allow resize */ + out_uint16_le(s, self->bitmap_compression); /* Support compression */ + out_uint16_le(s, 0); /* Unknown */ + out_uint16_le(s, 1); /* Unknown */ + out_uint16_le(s, 0); /* Pad */ + return 0; } /******************************************************************************/ /* Output order capability set */ static int APP_CC -rdp_rdp_out_order_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_order_caps(struct rdp_rdp *self, struct stream *s) { - char order_caps[32]; + char order_caps[32]; - g_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] = self->bitmap_cache; /* memblt */ - order_caps[4] = 0; /* triblt */ - order_caps[8] = 1; /* line */ - order_caps[9] = 1; /* line */ - order_caps[10] = 1; /* rect */ - order_caps[11] = self->desktop_save; /* desksave */ - order_caps[13] = 1; /* memblt another above */ - order_caps[14] = 1; /* triblt another above */ - order_caps[20] = self->polygon_ellipse_orders; /* polygon */ - order_caps[21] = self->polygon_ellipse_orders; /* polygon2 */ - order_caps[22] = 0; /* todo polyline */ - order_caps[25] = self->polygon_ellipse_orders; /* ellipse */ - order_caps[26] = self->polygon_ellipse_orders; /* 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_le(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, self->desktop_save * 0x38400); /* Desktop cache size */ - out_uint32_le(s, 0); /* Unknown */ - out_uint32_le(s, 0x4e4); /* Unknown */ - return 0; + g_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] = self->bitmap_cache; /* memblt */ + order_caps[4] = 0; /* triblt */ + order_caps[8] = 1; /* line */ + order_caps[9] = 1; /* line */ + order_caps[10] = 1; /* rect */ + order_caps[11] = self->desktop_save; /* desksave */ + order_caps[13] = 1; /* memblt another above */ + order_caps[14] = 1; /* triblt another above */ + order_caps[20] = self->polygon_ellipse_orders; /* polygon */ + order_caps[21] = self->polygon_ellipse_orders; /* polygon2 */ + order_caps[22] = 0; /* todo polyline */ + order_caps[25] = self->polygon_ellipse_orders; /* ellipse */ + order_caps[26] = self->polygon_ellipse_orders; /* 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_le(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, self->desktop_save * 0x38400); /* Desktop cache size */ + out_uint32_le(s, 0); /* Unknown */ + out_uint32_le(s, 0x4e4); /* Unknown */ + return 0; } /******************************************************************************/ /* Output bitmap cache capability set */ static int APP_CC -rdp_rdp_out_bmpcache_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_bmpcache_caps(struct rdp_rdp *self, struct stream *s) { - int Bpp = 0; + int Bpp = 0; - out_uint16_le(s, RDP_CAPSET_BMPCACHE); - out_uint16_le(s, RDP_CAPLEN_BMPCACHE); - Bpp = (self->mod->rdp_bpp + 7) / 8; - 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 */ - return 0; + out_uint16_le(s, RDP_CAPSET_BMPCACHE); + out_uint16_le(s, RDP_CAPLEN_BMPCACHE); + Bpp = (self->mod->rdp_bpp + 7) / 8; + 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 */ + return 0; } /******************************************************************************/ /* Output control capability set */ static int APP_CC -rdp_rdp_out_control_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_control_caps(struct rdp_rdp *self, struct stream *s) { - out_uint16_le(s, RDP_CAPSET_CONTROL); - out_uint16_le(s, RDP_CAPLEN_CONTROL); - out_uint16_le(s, 0); /* Control capabilities */ - out_uint16_le(s, 0); /* Remote detach */ - out_uint16_le(s, 2); /* Control interest */ - out_uint16_le(s, 2); /* Detach interest */ - return 0; + out_uint16_le(s, RDP_CAPSET_CONTROL); + out_uint16_le(s, RDP_CAPLEN_CONTROL); + out_uint16_le(s, 0); /* Control capabilities */ + out_uint16_le(s, 0); /* Remote detach */ + out_uint16_le(s, 2); /* Control interest */ + out_uint16_le(s, 2); /* Detach interest */ + return 0; } /******************************************************************************/ /* Output activation capability set */ static int APP_CC -rdp_rdp_out_activate_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_activate_caps(struct rdp_rdp *self, struct stream *s) { - out_uint16_le(s, RDP_CAPSET_ACTIVATE); - out_uint16_le(s, RDP_CAPLEN_ACTIVATE); - out_uint16_le(s, 0); /* Help key */ - out_uint16_le(s, 0); /* Help index key */ - out_uint16_le(s, 0); /* Extended help key */ - out_uint16_le(s, 0); /* Window activate */ - return 0; + out_uint16_le(s, RDP_CAPSET_ACTIVATE); + out_uint16_le(s, RDP_CAPLEN_ACTIVATE); + out_uint16_le(s, 0); /* Help key */ + out_uint16_le(s, 0); /* Help index key */ + out_uint16_le(s, 0); /* Extended help key */ + out_uint16_le(s, 0); /* Window activate */ + return 0; } /******************************************************************************/ /* Output pointer capability set */ static int APP_CC -rdp_rdp_out_pointer_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_pointer_caps(struct rdp_rdp *self, struct stream *s) { - out_uint16_le(s, RDP_CAPSET_POINTER); - out_uint16_le(s, RDP_CAPLEN_POINTER_MONO); - out_uint16_le(s, 0); /* Color pointer */ - out_uint16_le(s, 20); /* Cache size */ - return 0; + out_uint16_le(s, RDP_CAPSET_POINTER); + out_uint16_le(s, RDP_CAPLEN_POINTER_MONO); + out_uint16_le(s, 0); /* Color pointer */ + out_uint16_le(s, 20); /* Cache size */ + return 0; } /******************************************************************************/ /* Output share capability set */ static int APP_CC -rdp_rdp_out_share_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_share_caps(struct rdp_rdp *self, struct stream *s) { - out_uint16_le(s, RDP_CAPSET_SHARE); - out_uint16_le(s, RDP_CAPLEN_SHARE); - out_uint16_le(s, 0); /* userid */ - out_uint16_le(s, 0); /* pad */ - return 0; + out_uint16_le(s, RDP_CAPSET_SHARE); + out_uint16_le(s, RDP_CAPLEN_SHARE); + out_uint16_le(s, 0); /* userid */ + out_uint16_le(s, 0); /* pad */ + return 0; } /******************************************************************************/ /* Output color cache capability set */ static int APP_CC -rdp_rdp_out_colcache_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_out_colcache_caps(struct rdp_rdp *self, struct 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_le(s, 0); /* pad */ - return 0; + out_uint16_le(s, RDP_CAPSET_COLCACHE); + out_uint16_le(s, RDP_CAPLEN_COLCACHE); + out_uint16_le(s, 6); /* cache size */ + out_uint16_le(s, 0); /* pad */ + return 0; } -static char 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 char 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 char caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 }; static char caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 }; -static char 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 +static char 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 int APP_CC -rdp_rdp_out_unknown_caps(struct rdp_rdp* self, struct stream* s, int id, - int length, char* caps) +rdp_rdp_out_unknown_caps(struct rdp_rdp *self, struct stream *s, int id, + int length, char *caps) { - out_uint16_le(s, id); - out_uint16_le(s, length); - out_uint8p(s, caps, length - 4); - return 0; + out_uint16_le(s, id); + out_uint16_le(s, length); + out_uint8p(s, caps, length - 4); + return 0; } #define RDP5_FLAG 0x0030 @@ -349,774 +358,843 @@ rdp_rdp_out_unknown_caps(struct rdp_rdp* self, struct stream* s, int id, /******************************************************************************/ /* Send a confirm active PDU */ static int APP_CC -rdp_rdp_send_confirm_active(struct rdp_rdp* self, struct stream* s) +rdp_rdp_send_confirm_active(struct rdp_rdp *self, struct stream *s) { - int sec_flags; - int caplen; + int sec_flags; + int caplen; - sec_flags = SEC_ENCRYPT; - //sec_flags = RDP5_FLAG | SEC_ENCRYPT; - caplen = RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER + - RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE + - RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + - RDP_CAPLEN_POINTER_MONO + RDP_CAPLEN_SHARE + - 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + - 4 /* w2k fix, why? */ ; - if (rdp_sec_init(self->sec_layer, s, sec_flags) != 0) - { - return 1; - } - 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, (self->sec_layer->mcs_layer->userid + 1001)); - out_uint32_le(s, self->share_id); - 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, 0xd); /* num_caps */ - out_uint8s(s, 2); /* pad */ - rdp_rdp_out_general_caps(self, s); - rdp_rdp_out_bitmap_caps(self, s); - rdp_rdp_out_order_caps(self, s); - rdp_rdp_out_bmpcache_caps(self, s); - rdp_rdp_out_colcache_caps(self, s); - rdp_rdp_out_activate_caps(self, s); - rdp_rdp_out_control_caps(self, s); - rdp_rdp_out_pointer_caps(self, s); - rdp_rdp_out_share_caps(self, s); - rdp_rdp_out_unknown_caps(self, s, 0x0d, 0x58, caps_0x0d); /* international? */ - rdp_rdp_out_unknown_caps(self, s, 0x0c, 0x08, caps_0x0c); - rdp_rdp_out_unknown_caps(self, s, 0x0e, 0x08, caps_0x0e); - rdp_rdp_out_unknown_caps(self, s, 0x10, 0x34, caps_0x10); /* glyph cache? */ - s_mark_end(s); - if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) - { - return 1; - } - return 0; + sec_flags = SEC_ENCRYPT; + //sec_flags = RDP5_FLAG | SEC_ENCRYPT; + caplen = RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER + + RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE + + RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + + RDP_CAPLEN_POINTER_MONO + RDP_CAPLEN_SHARE + + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + + 4 /* w2k fix, why? */ ; + + if (rdp_sec_init(self->sec_layer, s, sec_flags) != 0) + { + return 1; + } + + 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, (self->sec_layer->mcs_layer->userid + 1001)); + out_uint32_le(s, self->share_id); + 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, 0xd); /* num_caps */ + out_uint8s(s, 2); /* pad */ + rdp_rdp_out_general_caps(self, s); + rdp_rdp_out_bitmap_caps(self, s); + rdp_rdp_out_order_caps(self, s); + rdp_rdp_out_bmpcache_caps(self, s); + rdp_rdp_out_colcache_caps(self, s); + rdp_rdp_out_activate_caps(self, s); + rdp_rdp_out_control_caps(self, s); + rdp_rdp_out_pointer_caps(self, s); + rdp_rdp_out_share_caps(self, s); + rdp_rdp_out_unknown_caps(self, s, 0x0d, 0x58, caps_0x0d); /* international? */ + rdp_rdp_out_unknown_caps(self, s, 0x0c, 0x08, caps_0x0c); + rdp_rdp_out_unknown_caps(self, s, 0x0e, 0x08, caps_0x0e); + rdp_rdp_out_unknown_caps(self, s, 0x10, 0x34, caps_0x10); /* glyph cache? */ + s_mark_end(s); + + if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) + { + return 1; + } + + return 0; } /******************************************************************************/ /* Process a color pointer PDU */ static int APP_CC -rdp_rdp_process_color_pointer_pdu(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_color_pointer_pdu(struct rdp_rdp *self, struct stream *s) { - int cache_idx; - int dlen; - int mlen; - struct rdp_cursor* cursor; + int cache_idx; + int dlen; + int mlen; + struct rdp_cursor *cursor; - in_uint16_le(s, cache_idx); - if (cache_idx >= sizeof(self->cursors) / sizeof(cursor)) - { - return 1; - } - cursor = self->cursors + cache_idx; - in_uint16_le(s, cursor->x); - in_uint16_le(s, cursor->y); - in_uint16_le(s, cursor->width); - in_uint16_le(s, cursor->height); - in_uint16_le(s, mlen); /* mask length */ - in_uint16_le(s, dlen); /* data length */ - if ((mlen > sizeof(cursor->mask)) || (dlen > sizeof(cursor->data))) - { - return 1; - } - in_uint8a(s, cursor->data, dlen); - in_uint8a(s, cursor->mask, mlen); - self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, - cursor->data, cursor->mask); - return 0; + in_uint16_le(s, cache_idx); + + if (cache_idx >= sizeof(self->cursors) / sizeof(cursor)) + { + return 1; + } + + cursor = self->cursors + cache_idx; + in_uint16_le(s, cursor->x); + in_uint16_le(s, cursor->y); + in_uint16_le(s, cursor->width); + in_uint16_le(s, cursor->height); + in_uint16_le(s, mlen); /* mask length */ + in_uint16_le(s, dlen); /* data length */ + + if ((mlen > sizeof(cursor->mask)) || (dlen > sizeof(cursor->data))) + { + return 1; + } + + in_uint8a(s, cursor->data, dlen); + in_uint8a(s, cursor->mask, mlen); + self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, + cursor->data, cursor->mask); + return 0; } /******************************************************************************/ /* Process a cached pointer PDU */ static int APP_CC -rdp_rdp_process_cached_pointer_pdu(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_cached_pointer_pdu(struct rdp_rdp *self, struct stream *s) { - int cache_idx; - struct rdp_cursor* cursor; + int cache_idx; + struct rdp_cursor *cursor; - in_uint16_le(s, cache_idx); - if (cache_idx >= sizeof(self->cursors) / sizeof(cursor)) - { - return 1; - } - cursor = self->cursors + cache_idx; - self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, - cursor->data, cursor->mask); - return 0; + in_uint16_le(s, cache_idx); + + if (cache_idx >= sizeof(self->cursors) / sizeof(cursor)) + { + return 1; + } + + cursor = self->cursors + cache_idx; + self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, + cursor->data, cursor->mask); + return 0; } /******************************************************************************/ /* Process a system pointer PDU */ static int APP_CC -rdp_rdp_process_system_pointer_pdu(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_system_pointer_pdu(struct rdp_rdp *self, struct stream *s) { - int system_pointer_type; - struct rdp_cursor* cursor; + int system_pointer_type; + struct rdp_cursor *cursor; - in_uint16_le(s, system_pointer_type); - switch (system_pointer_type) - { - case RDP_NULL_POINTER: - cursor = (struct rdp_cursor*)g_malloc(sizeof(struct rdp_cursor), 1); - g_memset(cursor->mask, 0xff, sizeof(cursor->mask)); - self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, - cursor->data, cursor->mask); - g_free(cursor); - break; - default: - break; - } - return 0; + in_uint16_le(s, system_pointer_type); + + switch (system_pointer_type) + { + case RDP_NULL_POINTER: + cursor = (struct rdp_cursor *)g_malloc(sizeof(struct rdp_cursor), 1); + g_memset(cursor->mask, 0xff, sizeof(cursor->mask)); + self->mod->server_set_cursor(self->mod, cursor->x, cursor->y, + cursor->data, cursor->mask); + g_free(cursor); + break; + default: + break; + } + + return 0; } /******************************************************************************/ /* Process a pointer PDU */ static int APP_CC -rdp_rdp_process_pointer_pdu(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_pointer_pdu(struct rdp_rdp *self, struct stream *s) { - int message_type; - int x; - int y; - int rv; + int message_type; + int x; + int y; + int rv; - rv = 0; - 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); - break; - case RDP_POINTER_COLOR: - rv = rdp_rdp_process_color_pointer_pdu(self, s); - break; - case RDP_POINTER_CACHED: - rv = rdp_rdp_process_cached_pointer_pdu(self, s); - break; - case RDP_POINTER_SYSTEM: - rv = rdp_rdp_process_system_pointer_pdu(self, s); - break; - default: - break; - } - return rv; + rv = 0; + 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); + break; + case RDP_POINTER_COLOR: + rv = rdp_rdp_process_color_pointer_pdu(self, s); + break; + case RDP_POINTER_CACHED: + rv = rdp_rdp_process_cached_pointer_pdu(self, s); + break; + case RDP_POINTER_SYSTEM: + rv = rdp_rdp_process_system_pointer_pdu(self, s); + break; + default: + break; + } + + return rv; } /******************************************************************************/ /* Process bitmap updates */ static void APP_CC -rdp_rdp_process_bitmap_updates(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_bitmap_updates(struct rdp_rdp *self, struct stream *s) { - int num_updates = 0; - int left = 0; - int top = 0; - int right = 0; - int bottom = 0; - int width = 0; - int height = 0; - int cx = 0; - int cy = 0; - int bpp = 0; - int Bpp = 0; - int compress = 0; - int bufsize = 0; - int size = 0; - int i = 0; - int x = 0; - int y = 0; - char* data = NULL; - char* bmpdata0 = NULL; - char* bmpdata1 = NULL; + int num_updates = 0; + int left = 0; + int top = 0; + int right = 0; + int bottom = 0; + int width = 0; + int height = 0; + int cx = 0; + int cy = 0; + int bpp = 0; + int Bpp = 0; + int compress = 0; + int bufsize = 0; + int size = 0; + int i = 0; + int x = 0; + int y = 0; + char *data = NULL; + char *bmpdata0 = NULL; + char *bmpdata1 = NULL; - 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; - bmpdata0 = (char*)g_malloc(width * height * Bpp, 0); - if (compress) + in_uint16_le(s, num_updates); + + for (i = 0; i < num_updates; i++) { - 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); - rdp_bitmap_decompress(bmpdata0, width, height, data, size, Bpp); - bmpdata1 = rdp_orders_convert_bitmap(bpp, self->mod->xrdp_bpp, - bmpdata0, width, height, - self->colormap.colors); - self->mod->server_paint_rect(self->mod, left, top, cx, cy, bmpdata1, - width, height, 0, 0); - } - else /* not compressed */ - { - for (y = 0; y < height; y++) - { - data = bmpdata0 + ((height - y) - 1) * (width * Bpp); - if (Bpp == 1) + 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; + bmpdata0 = (char *)g_malloc(width * height * Bpp, 0); + + if (compress) { - for (x = 0; x < width; x++) - { - in_uint8(s, data[x]); - } + 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); + rdp_bitmap_decompress(bmpdata0, width, height, data, size, Bpp); + bmpdata1 = rdp_orders_convert_bitmap(bpp, self->mod->xrdp_bpp, + bmpdata0, width, height, + self->colormap.colors); + self->mod->server_paint_rect(self->mod, left, top, cx, cy, bmpdata1, + width, height, 0, 0); } - else if (Bpp == 2) + else /* not compressed */ { - for (x = 0; x < width; x++) - { - in_uint16_le(s, ((tui16*)data)[x]); - } + for (y = 0; y < height; y++) + { + data = bmpdata0 + ((height - y) - 1) * (width * Bpp); + + if (Bpp == 1) + { + for (x = 0; x < width; x++) + { + in_uint8(s, data[x]); + } + } + else if (Bpp == 2) + { + for (x = 0; x < width; x++) + { + in_uint16_le(s, ((tui16 *)data)[x]); + } + } + else if (Bpp == 3) + { + for (x = 0; x < width; x++) + { + in_uint8(s, data[x * 3 + 0]); + in_uint8(s, data[x * 3 + 1]); + in_uint8(s, data[x * 3 + 2]); + } + } + } + + bmpdata1 = rdp_orders_convert_bitmap(bpp, self->mod->xrdp_bpp, + bmpdata0, width, height, + self->colormap.colors); + self->mod->server_paint_rect(self->mod, left, top, cx, cy, bmpdata1, + width, height, 0, 0); } - else if (Bpp == 3) + + if (bmpdata0 != bmpdata1) { - for (x = 0; x < width; x++) - { - in_uint8(s, data[x * 3 + 0]); - in_uint8(s, data[x * 3 + 1]); - in_uint8(s, data[x * 3 + 2]); - } + g_free(bmpdata1); } - } - bmpdata1 = rdp_orders_convert_bitmap(bpp, self->mod->xrdp_bpp, - bmpdata0, width, height, - self->colormap.colors); - self->mod->server_paint_rect(self->mod, left, top, cx, cy, bmpdata1, - width, height, 0, 0); + + g_free(bmpdata0); } - if (bmpdata0 != bmpdata1) - { - g_free(bmpdata1); - } - g_free(bmpdata0); - } } /******************************************************************************/ /* Process a palette update */ static void APP_CC -rdp_rdp_process_palette(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_palette(struct rdp_rdp *self, struct stream *s) { - int i; - int r; - int g; - int b; + int i; + int r; + int g; + int b; - in_uint8s(s, 2); /* pad */ - in_uint16_le(s, self->colormap.ncolors); - in_uint8s(s, 2); /* pad */ - for (i = 0; i < self->colormap.ncolors; i++) - { - in_uint8(s, r); - in_uint8(s, g); - in_uint8(s, b); - self->colormap.colors[i] = (r << 16) | (g << 8) | b; - } - //ui_set_colormap(hmap); + in_uint8s(s, 2); /* pad */ + in_uint16_le(s, self->colormap.ncolors); + in_uint8s(s, 2); /* pad */ + + for (i = 0; i < self->colormap.ncolors; i++) + { + in_uint8(s, r); + in_uint8(s, g); + in_uint8(s, b); + self->colormap.colors[i] = (r << 16) | (g << 8) | b; + } + + //ui_set_colormap(hmap); } /******************************************************************************/ /* Process an update PDU */ static int APP_CC -rdp_rdp_process_update_pdu(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_update_pdu(struct rdp_rdp *self, struct stream *s) { - int update_type; - int count; + int update_type; + int count; - in_uint16_le(s, update_type); - self->mod->server_begin_update(self->mod); - switch (update_type) - { - case RDP_UPDATE_ORDERS: - in_uint8s(s, 2); /* pad */ - in_uint16_le(s, count); - in_uint8s(s, 2); /* pad */ - rdp_orders_process_orders(self->orders, s, count); - break; - case RDP_UPDATE_BITMAP: - rdp_rdp_process_bitmap_updates(self, s); - break; - case RDP_UPDATE_PALETTE: - rdp_rdp_process_palette(self, s); - break; - case RDP_UPDATE_SYNCHRONIZE: - break; - default: - break; - } - self->mod->server_end_update(self->mod); - return 0; + in_uint16_le(s, update_type); + self->mod->server_begin_update(self->mod); + + switch (update_type) + { + case RDP_UPDATE_ORDERS: + in_uint8s(s, 2); /* pad */ + in_uint16_le(s, count); + in_uint8s(s, 2); /* pad */ + rdp_orders_process_orders(self->orders, s, count); + break; + case RDP_UPDATE_BITMAP: + rdp_rdp_process_bitmap_updates(self, s); + break; + case RDP_UPDATE_PALETTE: + rdp_rdp_process_palette(self, s); + break; + case RDP_UPDATE_SYNCHRONIZE: + break; + default: + break; + } + + self->mod->server_end_update(self->mod); + return 0; } /******************************************************************************/ void APP_CC -rdp_rdp_out_unistr(struct stream* s, char* text) +rdp_rdp_out_unistr(struct stream *s, char *text) { - int i; + int i; + + i = 0; + + while (text[i] != 0) + { + out_uint8(s, text[i]); + out_uint8(s, 0); + i++; + } - i = 0; - while (text[i] != 0) - { - out_uint8(s, text[i]); out_uint8(s, 0); - i++; - } - out_uint8(s, 0); - out_uint8(s, 0); + out_uint8(s, 0); } /******************************************************************************/ int APP_CC -rdp_rdp_send_login_info(struct rdp_rdp* self, int flags) +rdp_rdp_send_login_info(struct rdp_rdp *self, int flags) { - int len_domain; - int len_username; - int len_password; - int len_program; - int len_directory; - int sec_flags; - struct stream* s; + int len_domain; + int len_username; + int len_password; + int len_program; + int len_directory; + int sec_flags; + struct stream *s; + + DEBUG(("in rdp_rdp_send_login_info")); + make_stream(s); + init_stream(s, 8192); + len_domain = 2 * g_strlen(self->mod->domain); + len_username = 2 * g_strlen(self->mod->username); + len_password = 2 * g_strlen(self->mod->password); + len_program = 2 * g_strlen(self->mod->program); + len_directory = 2 * g_strlen(self->mod->directory); + sec_flags = SEC_LOGON_INFO | SEC_ENCRYPT; + + if (rdp_sec_init(self->sec_layer, s, sec_flags) != 0) + { + free_stream(s); + DEBUG(("out rdp_rdp_send_login_info error 1")); + return 1; + } + + out_uint32_le(s, 0); + out_uint32_le(s, flags); + out_uint16_le(s, len_domain); + out_uint16_le(s, len_username); + out_uint16_le(s, len_password); + out_uint16_le(s, len_program); + out_uint16_le(s, len_directory); + rdp_rdp_out_unistr(s, self->mod->domain); + rdp_rdp_out_unistr(s, self->mod->username); + rdp_rdp_out_unistr(s, self->mod->password); + rdp_rdp_out_unistr(s, self->mod->program); + rdp_rdp_out_unistr(s, self->mod->directory); + s_mark_end(s); + + if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) + { + free_stream(s); + DEBUG(("out rdp_rdp_send_login_info error 2")); + return 1; + } - DEBUG(("in rdp_rdp_send_login_info")); - make_stream(s); - init_stream(s, 8192); - len_domain = 2 * g_strlen(self->mod->domain); - len_username = 2 * g_strlen(self->mod->username); - len_password = 2 * g_strlen(self->mod->password); - len_program = 2 * g_strlen(self->mod->program); - len_directory = 2 * g_strlen(self->mod->directory); - sec_flags = SEC_LOGON_INFO | SEC_ENCRYPT; - if (rdp_sec_init(self->sec_layer, s, sec_flags) != 0) - { free_stream(s); - DEBUG(("out rdp_rdp_send_login_info error 1")); - return 1; - } - out_uint32_le(s, 0); - out_uint32_le(s, flags); - out_uint16_le(s, len_domain); - out_uint16_le(s, len_username); - out_uint16_le(s, len_password); - out_uint16_le(s, len_program); - out_uint16_le(s, len_directory); - rdp_rdp_out_unistr(s, self->mod->domain); - rdp_rdp_out_unistr(s, self->mod->username); - rdp_rdp_out_unistr(s, self->mod->password); - rdp_rdp_out_unistr(s, self->mod->program); - rdp_rdp_out_unistr(s, self->mod->directory); - s_mark_end(s); - if (rdp_sec_send(self->sec_layer, s, sec_flags) != 0) - { - free_stream(s); - DEBUG(("out rdp_rdp_send_login_info error 2")); - return 1; - } - free_stream(s); - DEBUG(("out rdp_rdp_send_login_info")); - return 0; + DEBUG(("out rdp_rdp_send_login_info")); + return 0; } /******************************************************************************/ int APP_CC -rdp_rdp_connect(struct rdp_rdp* self, char* ip, char* port) +rdp_rdp_connect(struct rdp_rdp *self, char *ip, char *port) { - int flags; + int flags; - DEBUG(("in rdp_rdp_connect")); - flags = RDP_LOGON_NORMAL; - if (g_strlen(self->mod->password) > 0) - { - flags |= RDP_LOGON_AUTO; - } - if (rdp_sec_connect(self->sec_layer, ip, port) != 0) - { - DEBUG(("out rdp_rdp_connect error rdp_sec_connect failed")); - return 1; - } - if (rdp_rdp_send_login_info(self, flags) != 0) - { - DEBUG(("out rdp_rdp_connect error rdp_rdp_send_login_info failed")); - return 1; - } - DEBUG(("out rdp_rdp_connect")); - return 0; + DEBUG(("in rdp_rdp_connect")); + flags = RDP_LOGON_NORMAL; + + if (g_strlen(self->mod->password) > 0) + { + flags |= RDP_LOGON_AUTO; + } + + if (rdp_sec_connect(self->sec_layer, ip, port) != 0) + { + DEBUG(("out rdp_rdp_connect error rdp_sec_connect failed")); + return 1; + } + + if (rdp_rdp_send_login_info(self, flags) != 0) + { + DEBUG(("out rdp_rdp_connect error rdp_rdp_send_login_info failed")); + return 1; + } + + DEBUG(("out rdp_rdp_connect")); + return 0; } /******************************************************************************/ int APP_CC -rdp_rdp_send_input(struct rdp_rdp* self, struct stream* s, +rdp_rdp_send_input(struct rdp_rdp *self, struct stream *s, int time, int message_type, int device_flags, int param1, int param2) { - if (rdp_rdp_init_data(self, s) != 0) - { - return 1; - } - out_uint16_le(s, 1); /* number of events */ - out_uint16_le(s, 0); - 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); - if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_INPUT) != 0) - { - return 1; - } - return 0; + if (rdp_rdp_init_data(self, s) != 0) + { + return 1; + } + + out_uint16_le(s, 1); /* number of events */ + out_uint16_le(s, 0); + 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); + + if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_INPUT) != 0) + { + return 1; + } + + return 0; } /******************************************************************************/ int APP_CC -rdp_rdp_send_invalidate(struct rdp_rdp* self, struct stream* s, +rdp_rdp_send_invalidate(struct rdp_rdp *self, struct stream *s, int left, int top, int width, int height) { - if (rdp_rdp_init_data(self, s) != 0) - { - return 1; - } - out_uint32_le(s, 1); - out_uint16_le(s, left); - out_uint16_le(s, top); - out_uint16_le(s, (left + width) - 1); - out_uint16_le(s, (top + height) - 1); - s_mark_end(s); - if (rdp_rdp_send_data(self, s, 33) != 0) - { - return 1; - } - return 0; + if (rdp_rdp_init_data(self, s) != 0) + { + return 1; + } + + out_uint32_le(s, 1); + out_uint16_le(s, left); + out_uint16_le(s, top); + out_uint16_le(s, (left + width) - 1); + out_uint16_le(s, (top + height) - 1); + s_mark_end(s); + + if (rdp_rdp_send_data(self, s, 33) != 0) + { + return 1; + } + + return 0; } /******************************************************************************/ int APP_CC -rdp_rdp_recv(struct rdp_rdp* self, struct stream* s, int* type) +rdp_rdp_recv(struct rdp_rdp *self, struct stream *s, int *type) { - int len; - int pdu_type; - int chan; + int len; + int pdu_type; + int chan; - chan = 0; - DEBUG(("in rdp_rdp_recv")); - if (s->next_packet >= s->end || s->next_packet == 0) - { - if (rdp_sec_recv(self->sec_layer, s, &chan) != 0) + chan = 0; + DEBUG(("in rdp_rdp_recv")); + + if (s->next_packet >= s->end || s->next_packet == 0) { - DEBUG(("error in rdp_rdp_recv, rdp_sec_recv failed")); - return 1; + if (rdp_sec_recv(self->sec_layer, s, &chan) != 0) + { + DEBUG(("error in rdp_rdp_recv, rdp_sec_recv failed")); + return 1; + } + + s->next_packet = s->p; } - s->next_packet = s->p; - } - else - { - chan = MCS_GLOBAL_CHANNEL; - s->p = s->next_packet; - } - if (chan == MCS_GLOBAL_CHANNEL) - { - in_uint16_le(s, len); - DEBUG(("rdp_rdp_recv got %d len", len)); - if (len == 0x8000) + else { - s->next_packet += 8; - DEBUG(("out rdp_rdp_recv")); - return 0; + chan = MCS_GLOBAL_CHANNEL; + s->p = s->next_packet; } - in_uint16_le(s, pdu_type); - in_uint8s(s, 2); - *type = pdu_type & 0xf; - s->next_packet += len; - } - else - { - /* todo, process channel data */ - DEBUG(("got channel data channel %d", chan)); - s->next_packet = s->end; - } - DEBUG(("out rdp_rdp_recv")); - return 0; + + if (chan == MCS_GLOBAL_CHANNEL) + { + in_uint16_le(s, len); + DEBUG(("rdp_rdp_recv got %d len", len)); + + if (len == 0x8000) + { + s->next_packet += 8; + DEBUG(("out rdp_rdp_recv")); + return 0; + } + + in_uint16_le(s, pdu_type); + in_uint8s(s, 2); + *type = pdu_type & 0xf; + s->next_packet += len; + } + else + { + /* todo, process channel data */ + DEBUG(("got channel data channel %d", chan)); + s->next_packet = s->end; + } + + DEBUG(("out rdp_rdp_recv")); + return 0; } /******************************************************************************/ static int APP_CC -rdp_rdp_process_disconnect_pdu(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_disconnect_pdu(struct rdp_rdp *self, struct stream *s) { - return 0; + return 0; } /******************************************************************************/ int APP_CC -rdp_rdp_process_data_pdu(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_data_pdu(struct rdp_rdp *self, struct stream *s) { - int data_pdu_type; - int ctype; - int len; - int rv; + int data_pdu_type; + int ctype; + int len; + int rv; - rv = 0; - in_uint8s(s, 6); /* shareid, pad, streamid */ - in_uint16_le(s, len); - in_uint8(s, data_pdu_type); - in_uint8(s, ctype); - in_uint8s(s, 2); /* clen */ - switch (data_pdu_type) - { - case RDP_DATA_PDU_UPDATE: - rv = rdp_rdp_process_update_pdu(self, s); - break; - case RDP_DATA_PDU_CONTROL: - break; - case RDP_DATA_PDU_SYNCHRONISE: - break; - case RDP_DATA_PDU_POINTER: - rv = rdp_rdp_process_pointer_pdu(self, s); - break; - case RDP_DATA_PDU_PLAY_SOUND: - break; - case RDP_DATA_PDU_LOGON: - break; - case RDP_DATA_PDU_DISCONNECT: - rv = rdp_rdp_process_disconnect_pdu(self, s); - break; - default: - break; - } - return rv; + rv = 0; + in_uint8s(s, 6); /* shareid, pad, streamid */ + in_uint16_le(s, len); + in_uint8(s, data_pdu_type); + in_uint8(s, ctype); + in_uint8s(s, 2); /* clen */ + + switch (data_pdu_type) + { + case RDP_DATA_PDU_UPDATE: + rv = rdp_rdp_process_update_pdu(self, s); + break; + case RDP_DATA_PDU_CONTROL: + break; + case RDP_DATA_PDU_SYNCHRONISE: + break; + case RDP_DATA_PDU_POINTER: + rv = rdp_rdp_process_pointer_pdu(self, s); + break; + case RDP_DATA_PDU_PLAY_SOUND: + break; + case RDP_DATA_PDU_LOGON: + break; + case RDP_DATA_PDU_DISCONNECT: + rv = rdp_rdp_process_disconnect_pdu(self, s); + break; + default: + break; + } + + return rv; } /******************************************************************************/ /* Process a bitmap capability set */ static void APP_CC -rdp_rdp_process_general_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_general_caps(struct rdp_rdp *self, struct stream *s) { } /******************************************************************************/ /* Process a bitmap capability set */ static void APP_CC -rdp_rdp_process_bitmap_caps(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_bitmap_caps(struct rdp_rdp *self, struct stream *s) { - int width = 0; - int height = 0; - int bpp = 0; + int width = 0; + int height = 0; + int bpp = 0; - in_uint16_le(s, bpp); - in_uint8s(s, 6); - in_uint16_le(s, width); - in_uint16_le(s, height); - self->mod->rdp_bpp = bpp; - /* todo, call reset if needed and use width and height */ + in_uint16_le(s, bpp); + in_uint8s(s, 6); + in_uint16_le(s, width); + in_uint16_le(s, height); + self->mod->rdp_bpp = bpp; + /* todo, call reset if needed and use width and height */ } /******************************************************************************/ /* Process server capabilities */ /* returns error */ static int APP_CC -rdp_rdp_process_server_caps(struct rdp_rdp* self, struct stream* s, int len) +rdp_rdp_process_server_caps(struct rdp_rdp *self, struct stream *s, int len) { - int n = 0; - int ncapsets = 0; - int capset_type = 0; - int capset_length = 0; - char* next = NULL; - char* start = NULL; + int n = 0; + int ncapsets = 0; + int capset_type = 0; + int capset_length = 0; + char *next = NULL; + char *start = NULL; - start = s->p; - in_uint16_le(s, ncapsets); - in_uint8s(s, 2); /* pad */ - for (n = 0; n < ncapsets; n++) - { - if (s->p > start + len) + start = s->p; + in_uint16_le(s, ncapsets); + in_uint8s(s, 2); /* pad */ + + for (n = 0; n < ncapsets; n++) { - return 0; + if (s->p > start + len) + { + return 0; + } + + 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_rdp_process_general_caps(self, s); + break; + case RDP_CAPSET_BITMAP: + rdp_rdp_process_bitmap_caps(self, s); + break; + default: + break; + } + + s->p = next; } - 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_rdp_process_general_caps(self, s); - break; - case RDP_CAPSET_BITMAP: - rdp_rdp_process_bitmap_caps(self, s); - break; - default: - break; - } - s->p = next; - } - return 0; + + return 0; } /******************************************************************************/ /* Send a control PDU */ /* returns error */ static int APP_CC -rdp_rdp_send_control(struct rdp_rdp* self, struct stream* s, int action) +rdp_rdp_send_control(struct rdp_rdp *self, struct stream *s, int action) { - if (rdp_rdp_init_data(self, s) != 0) - { - return 1; - } - out_uint16_le(s, action); - out_uint16_le(s, 0); /* userid */ - out_uint32_le(s, 0); /* control id */ - s_mark_end(s); - if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_CONTROL) != 0) - { - return 1; - } - return 0; + if (rdp_rdp_init_data(self, s) != 0) + { + return 1; + } + + out_uint16_le(s, action); + out_uint16_le(s, 0); /* userid */ + out_uint32_le(s, 0); /* control id */ + s_mark_end(s); + + if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_CONTROL) != 0) + { + return 1; + } + + return 0; } /******************************************************************************/ /* Send a synchronisation PDU */ /* returns error */ static int APP_CC -rdp_rdp_send_synchronise(struct rdp_rdp* self, struct stream* s) +rdp_rdp_send_synchronise(struct rdp_rdp *self, struct stream *s) { - if (rdp_rdp_init_data(self, s) != 0) - { - return 1; - } - out_uint16_le(s, 1); /* type */ - out_uint16_le(s, 1002); - s_mark_end(s); - if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_SYNCHRONISE) != 0) - { - return 1; - } - return 0; + if (rdp_rdp_init_data(self, s) != 0) + { + return 1; + } + + out_uint16_le(s, 1); /* type */ + out_uint16_le(s, 1002); + s_mark_end(s); + + if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_SYNCHRONISE) != 0) + { + return 1; + } + + return 0; } /******************************************************************************/ /* Send an (empty) font information PDU */ static int APP_CC -rdp_rdp_send_fonts(struct rdp_rdp* self, struct stream* s, int seq) +rdp_rdp_send_fonts(struct rdp_rdp *self, struct stream *s, int seq) { - if (rdp_rdp_init_data(self, s) != 0) - { - return 1; - } - out_uint16_le(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); - if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_FONT2) != 0) - { - return 1; - } - return 0; + if (rdp_rdp_init_data(self, s) != 0) + { + return 1; + } + + out_uint16_le(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); + + if (rdp_rdp_send_data(self, s, RDP_DATA_PDU_FONT2) != 0) + { + return 1; + } + + return 0; } /******************************************************************************/ /* Respond to a demand active PDU */ int APP_CC -rdp_rdp_process_demand_active(struct rdp_rdp* self, struct stream* s) +rdp_rdp_process_demand_active(struct rdp_rdp *self, struct stream *s) { - int type = 0; - int len_src_descriptor = 0; - int len_combined_caps = 0; + int type = 0; + int len_src_descriptor = 0; + int len_combined_caps = 0; - in_uint32_le(s, self->share_id); - in_uint16_le(s, len_src_descriptor); - in_uint16_le(s, len_combined_caps); - in_uint8s(s, len_src_descriptor); - rdp_rdp_process_server_caps(self, s, len_combined_caps); - rdp_rdp_send_confirm_active(self, s); - rdp_rdp_send_synchronise(self, s); - rdp_rdp_send_control(self, s, RDP_CTL_COOPERATE); - rdp_rdp_send_control(self, s, RDP_CTL_REQUEST_CONTROL); - rdp_rdp_recv(self, s, &type); /* RDP_PDU_SYNCHRONIZE */ - rdp_rdp_recv(self, s, &type); /* RDP_CTL_COOPERATE */ - rdp_rdp_recv(self, s, &type); /* RDP_CTL_GRANT_CONTROL */ - rdp_rdp_send_input(self, s, 0, RDP_INPUT_SYNCHRONIZE, 0, 0, 0); - rdp_rdp_send_fonts(self, s, 1); - rdp_rdp_send_fonts(self, s, 2); - rdp_rdp_recv(self, s, &type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */ - rdp_orders_reset_state(self->orders); - return 0; + in_uint32_le(s, self->share_id); + in_uint16_le(s, len_src_descriptor); + in_uint16_le(s, len_combined_caps); + in_uint8s(s, len_src_descriptor); + rdp_rdp_process_server_caps(self, s, len_combined_caps); + rdp_rdp_send_confirm_active(self, s); + rdp_rdp_send_synchronise(self, s); + rdp_rdp_send_control(self, s, RDP_CTL_COOPERATE); + rdp_rdp_send_control(self, s, RDP_CTL_REQUEST_CONTROL); + rdp_rdp_recv(self, s, &type); /* RDP_PDU_SYNCHRONIZE */ + rdp_rdp_recv(self, s, &type); /* RDP_CTL_COOPERATE */ + rdp_rdp_recv(self, s, &type); /* RDP_CTL_GRANT_CONTROL */ + rdp_rdp_send_input(self, s, 0, RDP_INPUT_SYNCHRONIZE, 0, 0, 0); + rdp_rdp_send_fonts(self, s, 1); + rdp_rdp_send_fonts(self, s, 2); + rdp_rdp_recv(self, s, &type); /* RDP_PDU_UNKNOWN 0x28 (Fonts?) */ + rdp_orders_reset_state(self->orders); + return 0; } /******************************************************************************/ int APP_CC -rdp_rec_check_file(struct rdp_rdp* self) +rdp_rec_check_file(struct rdp_rdp *self) { - char file_name[256]; - int index = 0; - int len = 0; - struct stream* s = (struct stream *)NULL; + char file_name[256]; + int index = 0; + int len = 0; + struct stream *s = (struct stream *)NULL; - g_memset(file_name,0,sizeof(char) * 256); + g_memset(file_name, 0, sizeof(char) * 256); - if (self->rec_fd == 0) - { - index = 1; - g_sprintf(file_name, "rec%8.8d.rec", index); - while (g_file_exist(file_name)) + if (self->rec_fd == 0) { - index++; - if (index >= 9999) - { - return 1; - } - g_sprintf(file_name, "rec%8.8d.rec", index); + index = 1; + g_sprintf(file_name, "rec%8.8d.rec", index); + + while (g_file_exist(file_name)) + { + index++; + + if (index >= 9999) + { + return 1; + } + + g_sprintf(file_name, "rec%8.8d.rec", index); + } + + self->rec_fd = g_file_open(file_name); + make_stream(s); + init_stream(s, 8192); + out_uint8a(s, "XRDPREC1", 8); + out_uint8s(s, 8); + s_mark_end(s); + len = s->end - s->data; + g_file_write(self->rec_fd, s->data, len); + free_stream(s); } - self->rec_fd = g_file_open(file_name); - make_stream(s); - init_stream(s, 8192); - out_uint8a(s, "XRDPREC1", 8); - out_uint8s(s, 8); + + return 0; +} + +/******************************************************************************/ +int APP_CC +rdp_rec_write_item(struct rdp_rdp *self, struct stream *s) +{ + int len = 0; + int time = 0; + + if (self->rec_fd == 0) + { + return 1; + } + + time = g_time1(); + out_uint32_le(s, time); s_mark_end(s); len = s->end - s->data; + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); g_file_write(self->rec_fd, s->data, len); - free_stream(s); - } - return 0; -} - -/******************************************************************************/ -int APP_CC -rdp_rec_write_item(struct rdp_rdp* self, struct stream* s) -{ - int len = 0; - int time = 0; - - if (self->rec_fd == 0) - { - return 1; - } - time = g_time1(); - out_uint32_le(s, time); - s_mark_end(s); - len = s->end - s->data; - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - g_file_write(self->rec_fd, s->data, len); - return 0; + return 0; } diff --git a/rdp/rdp_sec.c b/rdp/rdp_sec.c index 5efab76e..bd0fe349 100644 --- a/rdp/rdp_sec.c +++ b/rdp/rdp_sec.c @@ -1,655 +1,713 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp secure layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * librdp secure layer + */ #include "rdp.h" static char g_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 }; +{ + 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 char g_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 }; +{ + 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 +}; /*****************************************************************************/ -struct rdp_sec* APP_CC -rdp_sec_create(struct rdp_rdp* owner) +struct rdp_sec *APP_CC +rdp_sec_create(struct rdp_rdp *owner) { - struct rdp_sec* self; + struct rdp_sec *self; - self = (struct rdp_sec*)g_malloc(sizeof(struct rdp_sec), 1); - self->rdp_layer = owner; - make_stream(self->client_mcs_data); - init_stream(self->client_mcs_data, 8192); - make_stream(self->server_mcs_data); - init_stream(self->server_mcs_data, 8192); - self->mcs_layer = rdp_mcs_create(self, self->client_mcs_data, - self->server_mcs_data); - if(self->decrypt_rc4_info!=NULL) - { - g_writeln("rdp_sec_create - decrypt_rc4_info already created !!!"); - } - self->decrypt_rc4_info = ssl_rc4_info_create(); - if(self->encrypt_rc4_info!=NULL) - { - g_writeln("rdp_sec_create - encrypt_rc4_info already created !!!"); - } - self->encrypt_rc4_info = ssl_rc4_info_create(); - self->lic_layer = rdp_lic_create(self); - return self; + self = (struct rdp_sec *)g_malloc(sizeof(struct rdp_sec), 1); + self->rdp_layer = owner; + make_stream(self->client_mcs_data); + init_stream(self->client_mcs_data, 8192); + make_stream(self->server_mcs_data); + init_stream(self->server_mcs_data, 8192); + self->mcs_layer = rdp_mcs_create(self, self->client_mcs_data, + self->server_mcs_data); + + if (self->decrypt_rc4_info != NULL) + { + g_writeln("rdp_sec_create - decrypt_rc4_info already created !!!"); + } + + self->decrypt_rc4_info = ssl_rc4_info_create(); + + if (self->encrypt_rc4_info != NULL) + { + g_writeln("rdp_sec_create - encrypt_rc4_info already created !!!"); + } + + self->encrypt_rc4_info = ssl_rc4_info_create(); + self->lic_layer = rdp_lic_create(self); + return self; } /*****************************************************************************/ void APP_CC -rdp_sec_delete(struct rdp_sec* self) +rdp_sec_delete(struct rdp_sec *self) { - if (self == 0) - { - return; - } - rdp_lic_delete(self->lic_layer); - rdp_mcs_delete(self->mcs_layer); - free_stream(self->client_mcs_data); - free_stream(self->server_mcs_data); - ssl_rc4_info_delete(self->decrypt_rc4_info); - ssl_rc4_info_delete(self->encrypt_rc4_info); - g_free(self); + if (self == 0) + { + return; + } + + rdp_lic_delete(self->lic_layer); + rdp_mcs_delete(self->mcs_layer); + free_stream(self->client_mcs_data); + free_stream(self->server_mcs_data); + ssl_rc4_info_delete(self->decrypt_rc4_info); + ssl_rc4_info_delete(self->encrypt_rc4_info); + g_free(self); } /*****************************************************************************/ /* Reduce key entropy from 64 to 40 bits */ static void APP_CC -rdp_sec_make_40bit(char* key) +rdp_sec_make_40bit(char *key) { - key[0] = 0xd1; - key[1] = 0x26; - key[2] = 0x9e; + key[0] = 0xd1; + key[1] = 0x26; + key[2] = 0x9e; } /*****************************************************************************/ /* returns error */ /* update an encryption key */ static int APP_CC -rdp_sec_update(char* key, char* update_key, int key_len) +rdp_sec_update(char *key, char *update_key, int key_len) { - char shasig[20]; - void* sha1_info; - void* md5_info; - void* rc4_info; + char shasig[20]; + void *sha1_info; + void *md5_info; + void *rc4_info; - sha1_info = ssl_sha1_info_create(); - md5_info = ssl_md5_info_create(); - rc4_info = ssl_rc4_info_create(); - ssl_sha1_clear(sha1_info); - ssl_sha1_transform(sha1_info, update_key, key_len); - ssl_sha1_transform(sha1_info, g_pad_54, 40); - ssl_sha1_transform(sha1_info, key, key_len); - ssl_sha1_complete(sha1_info, shasig); - ssl_md5_clear(md5_info); - ssl_md5_transform(md5_info, update_key, key_len); - ssl_md5_transform(md5_info, g_pad_92, 48); - ssl_md5_transform(md5_info, shasig, 20); - ssl_md5_complete(md5_info, key); - ssl_rc4_set_key(rc4_info, key, key_len); - ssl_rc4_crypt(rc4_info, key, key_len); - if (key_len == 8) - { - rdp_sec_make_40bit(key); - } - ssl_sha1_info_delete(sha1_info); - ssl_md5_info_delete(md5_info); - ssl_rc4_info_delete(rc4_info); - return 0; + sha1_info = ssl_sha1_info_create(); + md5_info = ssl_md5_info_create(); + rc4_info = ssl_rc4_info_create(); + ssl_sha1_clear(sha1_info); + ssl_sha1_transform(sha1_info, update_key, key_len); + ssl_sha1_transform(sha1_info, g_pad_54, 40); + ssl_sha1_transform(sha1_info, key, key_len); + ssl_sha1_complete(sha1_info, shasig); + ssl_md5_clear(md5_info); + ssl_md5_transform(md5_info, update_key, key_len); + ssl_md5_transform(md5_info, g_pad_92, 48); + ssl_md5_transform(md5_info, shasig, 20); + ssl_md5_complete(md5_info, key); + ssl_rc4_set_key(rc4_info, key, key_len); + ssl_rc4_crypt(rc4_info, key, key_len); + + if (key_len == 8) + { + rdp_sec_make_40bit(key); + } + + ssl_sha1_info_delete(sha1_info); + ssl_md5_info_delete(md5_info); + ssl_rc4_info_delete(rc4_info); + return 0; } /*****************************************************************************/ static void APP_CC -rdp_sec_decrypt(struct rdp_sec* self, char* data, int len) +rdp_sec_decrypt(struct rdp_sec *self, char *data, int len) { - if (self->decrypt_use_count == 4096) - { - rdp_sec_update(self->decrypt_key, self->decrypt_update_key, - self->rc4_key_len); - ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, - self->rc4_key_len); - self->decrypt_use_count = 0; - } - ssl_rc4_crypt(self->decrypt_rc4_info, data, len); - self->decrypt_use_count++; + if (self->decrypt_use_count == 4096) + { + rdp_sec_update(self->decrypt_key, self->decrypt_update_key, + self->rc4_key_len); + ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, + self->rc4_key_len); + self->decrypt_use_count = 0; + } + + ssl_rc4_crypt(self->decrypt_rc4_info, data, len); + self->decrypt_use_count++; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_sec_recv(struct rdp_sec* self, struct stream* s, int* chan) +rdp_sec_recv(struct rdp_sec *self, struct stream *s, int *chan) { - int flags; + int flags; - DEBUG((" in rdp_sec_recv")); - if (rdp_mcs_recv(self->mcs_layer, s, chan) != 0) - { - DEBUG((" error in rdp_sec_recv, rdp_mcs_recv failed")); - return 1; - } - in_uint32_le(s, flags); - DEBUG((" rdp_sec_recv flags %8.8x", flags)); - if (flags & SEC_ENCRYPT) /* 0x08 */ - { - in_uint8s(s, 8); /* signature */ - rdp_sec_decrypt(self, s->p, s->end - s->p); - } - if (flags & SEC_LICENCE_NEG) /* 0x80 */ - { - DEBUG((" in rdp_sec_recv, got SEC_LICENCE_NEG")); - rdp_lic_process(self->lic_layer, s); - *chan = 0; - } - DEBUG((" out rdp_sec_recv")); - return 0; + DEBUG((" in rdp_sec_recv")); + + if (rdp_mcs_recv(self->mcs_layer, s, chan) != 0) + { + DEBUG((" error in rdp_sec_recv, rdp_mcs_recv failed")); + return 1; + } + + in_uint32_le(s, flags); + DEBUG((" rdp_sec_recv flags %8.8x", flags)); + + if (flags & SEC_ENCRYPT) /* 0x08 */ + { + in_uint8s(s, 8); /* signature */ + rdp_sec_decrypt(self, s->p, s->end - s->p); + } + + if (flags & SEC_LICENCE_NEG) /* 0x80 */ + { + DEBUG((" in rdp_sec_recv, got SEC_LICENCE_NEG")); + rdp_lic_process(self->lic_layer, s); + *chan = 0; + } + + DEBUG((" out rdp_sec_recv")); + return 0; } /*****************************************************************************/ /* prepare client mcs data to send in mcs layer */ static void APP_CC -rdp_sec_out_mcs_data(struct rdp_sec* self) +rdp_sec_out_mcs_data(struct rdp_sec *self) { - struct stream* s; - int hostlen; - int length; + struct stream *s; + int hostlen; + int length; - s = self->client_mcs_data; - init_stream(s, 512); - self->rdp_layer->mod->hostname[15] = 0; /* limit length to 15 */ - hostlen = 2 * g_strlen(self->rdp_layer->mod->hostname); - length = 158 + 76 + 12 + 4; - /* 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, 212); /* length */ - out_uint16_le(s, 1); /* RDP version. 1 == RDP4, 4 == RDP5. */ - out_uint16_le(s, 8); - out_uint16_le(s, self->rdp_layer->mod->width); - out_uint16_le(s, self->rdp_layer->mod->height); - out_uint16_le(s, 0xca01); - out_uint16_le(s, 0xaa03); - out_uint32_le(s, self->rdp_layer->mod->keylayout); - out_uint32_le(s, 2600); /* Client build */ - /* Unicode name of client, padded to 32 bytes */ - rdp_rdp_out_unistr(s, self->rdp_layer->mod->hostname); - out_uint8s(s, 30 - hostlen); - out_uint32_le(s, 4); - out_uint32_le(s, 0); - out_uint32_le(s, 12); - out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */ - out_uint16_le(s, 0xca01); /* color depth? */ - out_uint16_le(s, 1); - out_uint32_le(s, 0); - out_uint8(s, self->rdp_layer->mod->rdp_bpp); - out_uint16_le(s, 0x0700); - out_uint8(s, 0); - out_uint32_le(s, 1); - out_uint8s(s, 64); /* End of client info */ - out_uint16_le(s, SEC_TAG_CLI_4); - out_uint16_le(s, 12); - out_uint32_le(s, 9); - out_uint32_le(s, 0); - /* Client encryption settings */ - out_uint16_le(s, SEC_TAG_CLI_CRYPT); - out_uint16_le(s, 12); /* length */ - /* encryption supported, 128-bit supported */ - out_uint32_le(s, 0x3); - out_uint32_le(s, 0); /* Unknown */ - s_mark_end(s); + s = self->client_mcs_data; + init_stream(s, 512); + self->rdp_layer->mod->hostname[15] = 0; /* limit length to 15 */ + hostlen = 2 * g_strlen(self->rdp_layer->mod->hostname); + length = 158 + 76 + 12 + 4; + /* 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, 212); /* length */ + out_uint16_le(s, 1); /* RDP version. 1 == RDP4, 4 == RDP5. */ + out_uint16_le(s, 8); + out_uint16_le(s, self->rdp_layer->mod->width); + out_uint16_le(s, self->rdp_layer->mod->height); + out_uint16_le(s, 0xca01); + out_uint16_le(s, 0xaa03); + out_uint32_le(s, self->rdp_layer->mod->keylayout); + out_uint32_le(s, 2600); /* Client build */ + /* Unicode name of client, padded to 32 bytes */ + rdp_rdp_out_unistr(s, self->rdp_layer->mod->hostname); + out_uint8s(s, 30 - hostlen); + out_uint32_le(s, 4); + out_uint32_le(s, 0); + out_uint32_le(s, 12); + out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */ + out_uint16_le(s, 0xca01); /* color depth? */ + out_uint16_le(s, 1); + out_uint32_le(s, 0); + out_uint8(s, self->rdp_layer->mod->rdp_bpp); + out_uint16_le(s, 0x0700); + out_uint8(s, 0); + out_uint32_le(s, 1); + out_uint8s(s, 64); /* End of client info */ + out_uint16_le(s, SEC_TAG_CLI_4); + out_uint16_le(s, 12); + out_uint32_le(s, 9); + out_uint32_le(s, 0); + /* Client encryption settings */ + out_uint16_le(s, SEC_TAG_CLI_CRYPT); + out_uint16_le(s, 12); /* length */ + /* encryption supported, 128-bit supported */ + out_uint32_le(s, 0x3); + out_uint32_le(s, 0); /* Unknown */ + s_mark_end(s); } /*****************************************************************************/ /* Parse a public key structure */ /* returns boolean */ static int APP_CC -rdp_sec_parse_public_key(struct rdp_sec* self, struct stream* s, - char* modulus, char* exponent) +rdp_sec_parse_public_key(struct rdp_sec *self, struct stream *s, + char *modulus, char *exponent) { - int magic; - int modulus_len; + int magic; + int modulus_len; - in_uint32_le(s, magic); - if (magic != SEC_RSA_MAGIC) - { - return 0; - } - in_uint32_le(s, modulus_len); - if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE) - { - return 0; - } - in_uint8s(s, 8); - in_uint8a(s, exponent, SEC_EXPONENT_SIZE); - in_uint8a(s, modulus, SEC_MODULUS_SIZE); - in_uint8s(s, SEC_PADDING_SIZE); - return s_check(s); + in_uint32_le(s, magic); + + if (magic != SEC_RSA_MAGIC) + { + return 0; + } + + in_uint32_le(s, modulus_len); + + if (modulus_len != SEC_MODULUS_SIZE + SEC_PADDING_SIZE) + { + return 0; + } + + in_uint8s(s, 8); + in_uint8a(s, exponent, SEC_EXPONENT_SIZE); + in_uint8a(s, modulus, SEC_MODULUS_SIZE); + in_uint8s(s, SEC_PADDING_SIZE); + return s_check(s); } /*****************************************************************************/ /* Parse a crypto information structure */ /* returns boolean */ static int APP_CC -rdp_sec_parse_crypt_info(struct rdp_sec* self, struct stream* s, - char* modulus, char* exponent) +rdp_sec_parse_crypt_info(struct rdp_sec *self, struct stream *s, + char *modulus, char *exponent) { - int random_len; - int rsa_info_len; - int flags; - int tag; - int length; - char* next_tag; - char* end; + int random_len; + int rsa_info_len; + int flags; + int tag; + int length; + char *next_tag; + char *end; - in_uint32_le(s, self->rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */ - in_uint32_le(s, self->crypt_level); /* 1 = low, 2 = medium, 3 = high */ - if (self->crypt_level == 0) /* no encryption */ - { - return 0; - } - in_uint32_le(s, random_len); - in_uint32_le(s, rsa_info_len); - if (random_len != SEC_RANDOM_SIZE) - { - return 0; - } - in_uint8a(s, self->server_random, random_len); - /* RSA info */ - end = s->p + rsa_info_len; - if (end > s->end) - { - return 0; - } - in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */ - if (flags & 1) - { - in_uint8s(s, 8); /* unknown */ - while (s->p < end) + in_uint32_le(s, self->rc4_key_size); /* 1 = 40-bit, 2 = 128-bit */ + in_uint32_le(s, self->crypt_level); /* 1 = low, 2 = medium, 3 = high */ + + if (self->crypt_level == 0) /* no encryption */ { - in_uint16_le(s, tag); - in_uint16_le(s, length); - next_tag = s->p + length; - DEBUG((" rdp_sec_parse_crypt_info tag %d length %d", tag, length)); - switch (tag) - { - case SEC_TAG_PUBKEY: - if (!rdp_sec_parse_public_key(self, s, modulus, exponent)) - { - return 0; - } - break; - case SEC_TAG_KEYSIG: - break; - default: - break; - } - s->p = next_tag; + return 0; } - } - else - { - /* todo */ - return 0; - } - return s_check_end(s); + + in_uint32_le(s, random_len); + in_uint32_le(s, rsa_info_len); + + if (random_len != SEC_RANDOM_SIZE) + { + return 0; + } + + in_uint8a(s, self->server_random, random_len); + /* RSA info */ + end = s->p + rsa_info_len; + + if (end > s->end) + { + return 0; + } + + in_uint32_le(s, flags); /* 1 = RDP4-style, 0x80000002 = X.509 */ + + if (flags & 1) + { + in_uint8s(s, 8); /* unknown */ + + while (s->p < end) + { + in_uint16_le(s, tag); + in_uint16_le(s, length); + next_tag = s->p + length; + DEBUG((" rdp_sec_parse_crypt_info tag %d length %d", tag, length)); + + switch (tag) + { + case SEC_TAG_PUBKEY: + + if (!rdp_sec_parse_public_key(self, s, modulus, exponent)) + { + return 0; + } + + break; + case SEC_TAG_KEYSIG: + break; + default: + break; + } + + s->p = next_tag; + } + } + else + { + /* todo */ + return 0; + } + + return s_check_end(s); } /*****************************************************************************/ static void APP_CC -rdp_sec_rsa_op(char* out, char* in, char* mod, char* exp) +rdp_sec_rsa_op(char *out, char *in, char *mod, char *exp) { - ssl_mod_exp(out, SEC_MODULUS_SIZE, /* 64 */ - in, SEC_RANDOM_SIZE, /* 32 */ - mod, SEC_MODULUS_SIZE, /* 64 */ - exp, SEC_EXPONENT_SIZE); /* 4 */ + ssl_mod_exp(out, SEC_MODULUS_SIZE, /* 64 */ + in, SEC_RANDOM_SIZE, /* 32 */ + mod, SEC_MODULUS_SIZE, /* 64 */ + exp, SEC_EXPONENT_SIZE); /* 4 */ } /*****************************************************************************/ void APP_CC -rdp_sec_hash_48(char* out, char* in, char* salt1, char* salt2, int salt) +rdp_sec_hash_48(char *out, char *in, char *salt1, char *salt2, int salt) { - int i; - void* sha1_info; - void* md5_info; - char pad[4]; - char sha1_sig[20]; - char md5_sig[16]; + int i; + void *sha1_info; + void *md5_info; + char pad[4]; + char sha1_sig[20]; + char md5_sig[16]; - sha1_info = ssl_sha1_info_create(); - md5_info = ssl_md5_info_create(); - for (i = 0; i < 3; i++) - { - g_memset(pad, salt + i, 4); - ssl_sha1_clear(sha1_info); - ssl_sha1_transform(sha1_info, pad, i + 1); - ssl_sha1_transform(sha1_info, in, 48); - ssl_sha1_transform(sha1_info, salt1, 32); - ssl_sha1_transform(sha1_info, salt2, 32); - ssl_sha1_complete(sha1_info, sha1_sig); + sha1_info = ssl_sha1_info_create(); + md5_info = ssl_md5_info_create(); + + for (i = 0; i < 3; i++) + { + g_memset(pad, salt + i, 4); + ssl_sha1_clear(sha1_info); + ssl_sha1_transform(sha1_info, pad, i + 1); + ssl_sha1_transform(sha1_info, in, 48); + ssl_sha1_transform(sha1_info, salt1, 32); + ssl_sha1_transform(sha1_info, salt2, 32); + ssl_sha1_complete(sha1_info, sha1_sig); + ssl_md5_clear(md5_info); + ssl_md5_transform(md5_info, in, 48); + ssl_md5_transform(md5_info, sha1_sig, 20); + ssl_md5_complete(md5_info, md5_sig); + g_memcpy(out + i * 16, md5_sig, 16); + } + + ssl_sha1_info_delete(sha1_info); + ssl_md5_info_delete(md5_info); +} + +/*****************************************************************************/ +void APP_CC +rdp_sec_hash_16(char *out, char *in, char *salt1, char *salt2) +{ + void *md5_info; + + md5_info = ssl_md5_info_create(); ssl_md5_clear(md5_info); - ssl_md5_transform(md5_info, in, 48); - ssl_md5_transform(md5_info, sha1_sig, 20); - ssl_md5_complete(md5_info, md5_sig); - g_memcpy(out + i * 16, md5_sig, 16); - } - ssl_sha1_info_delete(sha1_info); - ssl_md5_info_delete(md5_info); -} - -/*****************************************************************************/ -void APP_CC -rdp_sec_hash_16(char* out, char* in, char* salt1, char* salt2) -{ - void* md5_info; - - md5_info = ssl_md5_info_create(); - ssl_md5_clear(md5_info); - ssl_md5_transform(md5_info, in, 16); - ssl_md5_transform(md5_info, salt1, 32); - ssl_md5_transform(md5_info, salt2, 32); - ssl_md5_complete(md5_info, out); - ssl_md5_info_delete(md5_info); + ssl_md5_transform(md5_info, in, 16); + ssl_md5_transform(md5_info, salt1, 32); + ssl_md5_transform(md5_info, salt2, 32); + ssl_md5_complete(md5_info, out); + ssl_md5_info_delete(md5_info); } /*****************************************************************************/ static int APP_CC -rdp_sec_generate_keys(struct rdp_sec* self) +rdp_sec_generate_keys(struct rdp_sec *self) { - char session_key[48]; - char temp_hash[48]; - char input[48]; + char session_key[48]; + char temp_hash[48]; + char input[48]; - g_memcpy(input, self->client_random, 24); - g_memcpy(input + 24, self->server_random, 24); - rdp_sec_hash_48(temp_hash, input, self->client_random, - self->server_random, 65); - rdp_sec_hash_48(session_key, temp_hash, self->client_random, - self->server_random, 88); - g_memcpy(self->sign_key, session_key, 16); - rdp_sec_hash_16(self->decrypt_key, session_key + 16, self->client_random, - self->server_random); - rdp_sec_hash_16(self->encrypt_key, session_key + 32, self->client_random, - self->server_random); - DEBUG((" rdp_sec_generate_keys, rc4_key_size is %d", self->rc4_key_size)); - DEBUG((" rdp_sec_generate_keys, crypt_level is %d", self->crypt_level)); - if (self->rc4_key_size == 1) - { - rdp_sec_make_40bit(self->sign_key); - rdp_sec_make_40bit(self->encrypt_key); - rdp_sec_make_40bit(self->decrypt_key); - self->rc4_key_len = 8; - } - else - { - self->rc4_key_len = 16; - } - g_memcpy(self->decrypt_update_key, self->decrypt_key, 16); - g_memcpy(self->encrypt_update_key, self->encrypt_key, 16); - ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); - ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); - return 0; + g_memcpy(input, self->client_random, 24); + g_memcpy(input + 24, self->server_random, 24); + rdp_sec_hash_48(temp_hash, input, self->client_random, + self->server_random, 65); + rdp_sec_hash_48(session_key, temp_hash, self->client_random, + self->server_random, 88); + g_memcpy(self->sign_key, session_key, 16); + rdp_sec_hash_16(self->decrypt_key, session_key + 16, self->client_random, + self->server_random); + rdp_sec_hash_16(self->encrypt_key, session_key + 32, self->client_random, + self->server_random); + DEBUG((" rdp_sec_generate_keys, rc4_key_size is %d", self->rc4_key_size)); + DEBUG((" rdp_sec_generate_keys, crypt_level is %d", self->crypt_level)); + + if (self->rc4_key_size == 1) + { + rdp_sec_make_40bit(self->sign_key); + rdp_sec_make_40bit(self->encrypt_key); + rdp_sec_make_40bit(self->decrypt_key); + self->rc4_key_len = 8; + } + else + { + self->rc4_key_len = 16; + } + + g_memcpy(self->decrypt_update_key, self->decrypt_key, 16); + g_memcpy(self->encrypt_update_key, self->encrypt_key, 16); + ssl_rc4_set_key(self->decrypt_rc4_info, self->decrypt_key, self->rc4_key_len); + ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, self->rc4_key_len); + return 0; } /*****************************************************************************/ /* Process crypto information blob */ static void APP_CC -rdp_sec_process_crypt_info(struct rdp_sec* self, struct stream* s) +rdp_sec_process_crypt_info(struct rdp_sec *self, struct stream *s) { - char modulus[64]; - char exponent[64]; + char modulus[64]; + char exponent[64]; - g_memset(modulus, 0, sizeof(modulus)); - g_memset(exponent, 0, sizeof(exponent)); - if (!rdp_sec_parse_crypt_info(self, s, modulus, exponent)) - { - DEBUG((" error in rdp_sec_process_crypt_info")); - return; - } - /* Generate a client random, and determine encryption keys */ - g_random(self->client_random, 32); - rdp_sec_rsa_op(self->client_crypt_random, self->client_random, - modulus, exponent); - rdp_sec_generate_keys(self); + g_memset(modulus, 0, sizeof(modulus)); + g_memset(exponent, 0, sizeof(exponent)); + + if (!rdp_sec_parse_crypt_info(self, s, modulus, exponent)) + { + DEBUG((" error in rdp_sec_process_crypt_info")); + return; + } + + /* Generate a client random, and determine encryption keys */ + g_random(self->client_random, 32); + rdp_sec_rsa_op(self->client_crypt_random, self->client_random, + modulus, exponent); + rdp_sec_generate_keys(self); } /*****************************************************************************/ /* Process connect response data blob */ static void APP_CC -rdp_sec_process_mcs_data(struct rdp_sec* self) +rdp_sec_process_mcs_data(struct rdp_sec *self) { - int tag; - int length; - int len; - char* next_tag; - struct stream* s; + int tag; + int length; + int len; + char *next_tag; + struct stream *s; - s = self->server_mcs_data; - s->p = s->data; - in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */ - in_uint8(s, len); - if (len & 0x80) - { + s = self->server_mcs_data; + s->p = s->data; + in_uint8s(s, 21); /* header (T.124 ConferenceCreateResponse) */ in_uint8(s, len); - } - while (s->p < s->end) - { - in_uint16_le(s, tag); - in_uint16_le(s, length); - DEBUG((" rdp_sec_process_mcs_data tag %d length %d", tag, length)); - if (length <= 4) + + if (len & 0x80) { - return; + in_uint8(s, len); } - next_tag = (s->p + length) - 4; - switch (tag) + + while (s->p < s->end) { - case SEC_TAG_SRV_INFO: - //rdp_sec_process_srv_info(self, s); - break; - case SEC_TAG_SRV_CRYPT: - rdp_sec_process_crypt_info(self, s); - break; - case SEC_TAG_SRV_CHANNELS: - break; - default: - break; + in_uint16_le(s, tag); + in_uint16_le(s, length); + DEBUG((" rdp_sec_process_mcs_data tag %d length %d", tag, length)); + + if (length <= 4) + { + return; + } + + next_tag = (s->p + length) - 4; + + switch (tag) + { + case SEC_TAG_SRV_INFO: + //rdp_sec_process_srv_info(self, s); + break; + case SEC_TAG_SRV_CRYPT: + rdp_sec_process_crypt_info(self, s); + break; + case SEC_TAG_SRV_CHANNELS: + break; + default: + break; + } + + s->p = next_tag; } - s->p = next_tag; - } } /*****************************************************************************/ /* Transfer the client random to the server */ /* returns error */ static int APP_CC -rdp_sec_establish_key(struct rdp_sec* self) +rdp_sec_establish_key(struct rdp_sec *self) { - int length; - int flags; - struct stream* s; + int length; + int flags; + struct stream *s; + + DEBUG((" sending client random")); + make_stream(s); + init_stream(s, 8192); + length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE; + flags = SEC_CLIENT_RANDOM; + + if (rdp_sec_init(self, s, flags) != 0) + { + free_stream(s); + return 1; + } + + out_uint32_le(s, length); + out_uint8p(s, self->client_crypt_random, SEC_MODULUS_SIZE); + out_uint8s(s, SEC_PADDING_SIZE); + s_mark_end(s); + + if (rdp_sec_send(self, s, flags) != 0) + { + free_stream(s); + return 1; + } - DEBUG((" sending client random")); - make_stream(s); - init_stream(s, 8192); - length = SEC_MODULUS_SIZE + SEC_PADDING_SIZE; - flags = SEC_CLIENT_RANDOM; - if (rdp_sec_init(self, s, flags) != 0) - { free_stream(s); - return 1; - } - out_uint32_le(s, length); - out_uint8p(s, self->client_crypt_random, SEC_MODULUS_SIZE); - out_uint8s(s, SEC_PADDING_SIZE); - s_mark_end(s); - if (rdp_sec_send(self, s, flags) != 0) - { - free_stream(s); - return 1; - } - free_stream(s); - return 0; + return 0; } /*****************************************************************************/ /* Establish a secure connection */ int APP_CC -rdp_sec_connect(struct rdp_sec* self, char* ip, char* port) +rdp_sec_connect(struct rdp_sec *self, char *ip, char *port) { - DEBUG((" in rdp_sec_connect")); - rdp_sec_out_mcs_data(self); - if (rdp_mcs_connect(self->mcs_layer, ip, port) != 0) - { - DEBUG((" out rdp_sec_connect error rdp_mcs_connect failed")); - return 1; - } - rdp_sec_process_mcs_data(self); - if (rdp_sec_establish_key(self) != 0) - { - DEBUG((" out rdp_sec_connect error rdp_sec_establish_key failed")); - return 1; - } - DEBUG((" out rdp_sec_connect")); - return 0; + DEBUG((" in rdp_sec_connect")); + rdp_sec_out_mcs_data(self); + + if (rdp_mcs_connect(self->mcs_layer, ip, port) != 0) + { + DEBUG((" out rdp_sec_connect error rdp_mcs_connect failed")); + return 1; + } + + rdp_sec_process_mcs_data(self); + + if (rdp_sec_establish_key(self) != 0) + { + DEBUG((" out rdp_sec_connect error rdp_sec_establish_key failed")); + return 1; + } + + DEBUG((" out rdp_sec_connect")); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_sec_init(struct rdp_sec* self, struct stream* s, int flags) +rdp_sec_init(struct rdp_sec *self, struct stream *s, int flags) { - if (rdp_mcs_init(self->mcs_layer, s) != 0) - { - return 1; - } - if (flags & SEC_ENCRYPT) - { - s_push_layer(s, sec_hdr, 12); - } - else - { - s_push_layer(s, sec_hdr, 4); - } - return 0; + if (rdp_mcs_init(self->mcs_layer, s) != 0) + { + return 1; + } + + if (flags & SEC_ENCRYPT) + { + s_push_layer(s, sec_hdr, 12); + } + else + { + s_push_layer(s, sec_hdr, 4); + } + + return 0; } /*****************************************************************************/ /* Output a uint32 into a buffer (little-endian) */ void APP_CC -rdp_sec_buf_out_uint32(char* buffer, int value) +rdp_sec_buf_out_uint32(char *buffer, int value) { - buffer[0] = value & 0xff; - buffer[1] = (value >> 8) & 0xff; - buffer[2] = (value >> 16) & 0xff; - buffer[3] = (value >> 24) & 0xff; + 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 APP_CC -rdp_sec_sign(char* signature, int siglen, char* session_key, int keylen, - char* data, int datalen) +rdp_sec_sign(char *signature, int siglen, char *session_key, int keylen, + char *data, int datalen) { - char shasig[20]; - char md5sig[16]; - char lenhdr[4]; - void* sha1_context; - void* md5_context; + char shasig[20]; + char md5sig[16]; + char lenhdr[4]; + void *sha1_context; + void *md5_context; - rdp_sec_buf_out_uint32(lenhdr, datalen); - sha1_context = ssl_sha1_info_create(); - ssl_sha1_clear(sha1_context); - ssl_sha1_transform(sha1_context, session_key, keylen); - ssl_sha1_transform(sha1_context, g_pad_54, 40); - ssl_sha1_transform(sha1_context, lenhdr, 4); - ssl_sha1_transform(sha1_context, data, datalen); - ssl_sha1_complete(sha1_context, shasig); - ssl_sha1_info_delete(sha1_context); - md5_context = ssl_md5_info_create(); - ssl_md5_clear(md5_context); - ssl_md5_transform(md5_context, session_key, keylen); - ssl_md5_transform(md5_context, g_pad_92, 48); - ssl_md5_transform(md5_context, shasig, 20); - ssl_md5_complete(md5_context, md5sig); - ssl_md5_info_delete(md5_context); - g_memcpy(signature, md5sig, siglen); + rdp_sec_buf_out_uint32(lenhdr, datalen); + sha1_context = ssl_sha1_info_create(); + ssl_sha1_clear(sha1_context); + ssl_sha1_transform(sha1_context, session_key, keylen); + ssl_sha1_transform(sha1_context, g_pad_54, 40); + ssl_sha1_transform(sha1_context, lenhdr, 4); + ssl_sha1_transform(sha1_context, data, datalen); + ssl_sha1_complete(sha1_context, shasig); + ssl_sha1_info_delete(sha1_context); + md5_context = ssl_md5_info_create(); + ssl_md5_clear(md5_context); + ssl_md5_transform(md5_context, session_key, keylen); + ssl_md5_transform(md5_context, g_pad_92, 48); + ssl_md5_transform(md5_context, shasig, 20); + ssl_md5_complete(md5_context, md5sig); + ssl_md5_info_delete(md5_context); + g_memcpy(signature, md5sig, siglen); } /*****************************************************************************/ /* Encrypt data using RC4 */ static void APP_CC -rdp_sec_encrypt(struct rdp_sec* self, char* data, int length) +rdp_sec_encrypt(struct rdp_sec *self, char *data, int length) { - if (self->encrypt_use_count == 4096) - { - rdp_sec_update(self->encrypt_key, self->encrypt_update_key, - self->rc4_key_len); - ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, - self->rc4_key_len); - self->encrypt_use_count = 0; - } - ssl_rc4_crypt(self->encrypt_rc4_info, data, length); - self->encrypt_use_count++; + if (self->encrypt_use_count == 4096) + { + rdp_sec_update(self->encrypt_key, self->encrypt_update_key, + self->rc4_key_len); + ssl_rc4_set_key(self->encrypt_rc4_info, self->encrypt_key, + self->rc4_key_len); + self->encrypt_use_count = 0; + } + + ssl_rc4_crypt(self->encrypt_rc4_info, data, length); + self->encrypt_use_count++; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_sec_send(struct rdp_sec* self, struct stream* s, int flags) +rdp_sec_send(struct rdp_sec *self, struct stream *s, int flags) { - int datalen; + int datalen; - DEBUG((" in rdp_sec_send flags %8.8x", flags)); - s_pop_layer(s, sec_hdr); - out_uint32_le(s, flags); - if (flags & SEC_ENCRYPT) - { - datalen = (s->end - s->p) - 8; - rdp_sec_sign(s->p, 8, self->sign_key, self->rc4_key_len, s->p + 8, - datalen); - rdp_sec_encrypt(self, s->p + 8, datalen); - } - if (rdp_mcs_send(self->mcs_layer, s) != 0) - { - DEBUG((" out rdp_sec_send, rdp_mcs_send failed")); - return 1; - } - DEBUG((" out rdp_sec_send")); - return 0; + DEBUG((" in rdp_sec_send flags %8.8x", flags)); + s_pop_layer(s, sec_hdr); + out_uint32_le(s, flags); + + if (flags & SEC_ENCRYPT) + { + datalen = (s->end - s->p) - 8; + rdp_sec_sign(s->p, 8, self->sign_key, self->rc4_key_len, s->p + 8, + datalen); + rdp_sec_encrypt(self, s->p + 8, datalen); + } + + if (rdp_mcs_send(self->mcs_layer, s) != 0) + { + DEBUG((" out rdp_sec_send, rdp_mcs_send failed")); + return 1; + } + + DEBUG((" out rdp_sec_send")); + return 0; } diff --git a/rdp/rdp_tcp.c b/rdp/rdp_tcp.c index 0f053ff6..f3c990ad 100644 --- a/rdp/rdp_tcp.c +++ b/rdp/rdp_tcp.c @@ -1,178 +1,188 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - librdp tcp layer - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * librdp tcp layer + */ #include "rdp.h" /*****************************************************************************/ -struct rdp_tcp* APP_CC -rdp_tcp_create(struct rdp_iso* owner) +struct rdp_tcp *APP_CC +rdp_tcp_create(struct rdp_iso *owner) { - struct rdp_tcp* self; + struct rdp_tcp *self; - self = (struct rdp_tcp*)g_malloc(sizeof(struct rdp_tcp), 1); - self->iso_layer = owner; - return self; + self = (struct rdp_tcp *)g_malloc(sizeof(struct rdp_tcp), 1); + self->iso_layer = owner; + return self; } /*****************************************************************************/ void APP_CC -rdp_tcp_delete(struct rdp_tcp* self) +rdp_tcp_delete(struct rdp_tcp *self) { - g_free(self); + g_free(self); } /*****************************************************************************/ /* get out stream ready for data */ /* returns error */ int APP_CC -rdp_tcp_init(struct rdp_tcp* self, struct stream* s) +rdp_tcp_init(struct rdp_tcp *self, struct stream *s) { - init_stream(s, 8192); - return 0; + init_stream(s, 8192); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_tcp_recv(struct rdp_tcp* self, struct stream* s, int len) +rdp_tcp_recv(struct rdp_tcp *self, struct stream *s, int len) { - int rcvd; + int rcvd; - DEBUG((" in rdp_tcp_recv gota get %d bytes on sck %d", - len, self->sck)); - if (self->sck_closed) - { - DEBUG((" out rdp_tcp_recv error sck closed")); - return 1; - } - init_stream(s, len); - while (len > 0) - { - rcvd = g_tcp_recv(self->sck, s->end, len, 0); - if (rcvd == -1) + DEBUG((" in rdp_tcp_recv gota get %d bytes on sck %d", + len, self->sck)); + + if (self->sck_closed) { - if (g_tcp_last_error_would_block(self->sck)) - { - g_tcp_can_recv(self->sck, 10); - } - else - { - self->sck_closed = 1; - DEBUG((" out rdp_tcp_recv error unknown")); + DEBUG((" out rdp_tcp_recv error sck closed")); return 1; - } } - else if (rcvd == 0) + + init_stream(s, len); + + while (len > 0) { - self->sck_closed = 1; - DEBUG((" out rdp_tcp_recv error connection dropped")); - return 1; + rcvd = g_tcp_recv(self->sck, s->end, len, 0); + + if (rcvd == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + g_tcp_can_recv(self->sck, 10); + } + else + { + self->sck_closed = 1; + DEBUG((" out rdp_tcp_recv error unknown")); + return 1; + } + } + else if (rcvd == 0) + { + self->sck_closed = 1; + DEBUG((" out rdp_tcp_recv error connection dropped")); + return 1; + } + else + { + s->end += rcvd; + len -= rcvd; + } + } + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +rdp_tcp_send(struct rdp_tcp *self, struct stream *s) +{ + int len; + int total; + int sent; + + if (self->sck_closed) + { + DEBUG((" out rdp_tcp_send error sck closed")); + return 1; + } + + len = s->end - s->data; + DEBUG((" in rdp_tcp_send gota send %d bytes on sck %d", len, + self->sck)); + total = 0; + + while (total < len) + { + sent = g_tcp_send(self->sck, s->data + total, len - total, 0); + + if (sent == -1) + { + if (g_tcp_last_error_would_block(self->sck)) + { + g_tcp_can_send(self->sck, 10); + } + else + { + self->sck_closed = 1; + DEBUG((" out rdp_tcp_send error unknown")); + return 1; + } + } + else if (sent == 0) + { + self->sck_closed = 1; + DEBUG((" out rdp_tcp_send error connection dropped")); + return 1; + } + else + { + total = total + sent; + } + } + + return 0; +} + +/*****************************************************************************/ +/* returns error */ +int APP_CC +rdp_tcp_connect(struct rdp_tcp *self, char *ip, char *port) +{ + DEBUG((" in rdp_tcp_connect ip %s port %s", ip, port)); + self->sck = g_tcp_socket(); + + if (g_tcp_connect(self->sck, ip, port) == 0) + { + g_tcp_set_non_blocking(self->sck); } else { - s->end += rcvd; - len -= rcvd; - } - } - return 0; -} - -/*****************************************************************************/ -/* returns error */ -int APP_CC -rdp_tcp_send(struct rdp_tcp* self, struct stream* s) -{ - int len; - int total; - int sent; - - if (self->sck_closed) - { - DEBUG((" out rdp_tcp_send error sck closed")); - return 1; - } - len = s->end - s->data; - DEBUG((" in rdp_tcp_send gota send %d bytes on sck %d", len, - self->sck)); - total = 0; - while (total < len) - { - sent = g_tcp_send(self->sck, s->data + total, len - total, 0); - if (sent == -1) - { - if (g_tcp_last_error_would_block(self->sck)) - { - g_tcp_can_send(self->sck, 10); - } - else - { - self->sck_closed = 1; - DEBUG((" out rdp_tcp_send error unknown")); + DEBUG((" out rdp_tcp_connect error g_tcp_connect failed")); return 1; - } } - else if (sent == 0) - { - self->sck_closed = 1; - DEBUG((" out rdp_tcp_send error connection dropped")); - return 1; - } - else - { - total = total + sent; - } - } - return 0; + + DEBUG((" out rdp_tcp_connect")); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -rdp_tcp_connect(struct rdp_tcp* self, char* ip, char* port) +rdp_tcp_disconnect(struct rdp_tcp *self) { - DEBUG((" in rdp_tcp_connect ip %s port %s", ip, port)); - self->sck = g_tcp_socket(); - if (g_tcp_connect(self->sck, ip, port) == 0) - { - g_tcp_set_non_blocking(self->sck); - } - else - { - DEBUG((" out rdp_tcp_connect error g_tcp_connect failed")); - return 1; - } - DEBUG((" out rdp_tcp_connect")); - return 0; -} + if (self->sck != 0) + { + g_tcp_close(self->sck); + } -/*****************************************************************************/ -/* returns error */ -int APP_CC -rdp_tcp_disconnect(struct rdp_tcp* self) -{ - if (self->sck != 0) - { - g_tcp_close(self->sck); - } - self->sck = 0; - return 0; + self->sck = 0; + return 0; } diff --git a/readme.txt b/readme.txt index fe6c0726..e4d71703 100644 --- a/readme.txt +++ b/readme.txt @@ -35,4 +35,4 @@ make install see file-loc.txt to see what files are installed where -Jay +Jay Sorg diff --git a/sesman/access.c b/sesman/access.c index 0037de3f..00c9c381 100644 --- a/sesman/access.c +++ b/sesman/access.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -27,102 +26,102 @@ #include "sesman.h" -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ /******************************************************************************/ int DEFAULT_CC -access_login_allowed(char* user) +access_login_allowed(char *user) { - int gid; - int ok; + int gid; + int ok; + + if ((0 == g_strncmp(user, "root", 5)) && (0 == g_cfg->sec.allow_root)) + { + log_message(LOG_LEVEL_WARNING, + "ROOT login attempted, but root login is disabled"); + return 0; + } + + if (0 == g_cfg->sec.ts_users_enable) + { + LOG_DBG("Terminal Server Users group is disabled, allowing authentication", + 1); + return 1; + } + + if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0)) + { + log_message(LOG_LEVEL_ERROR, "Cannot read user info! - login denied"); + return 0; + } + + if (g_cfg->sec.ts_users == gid) + { + LOG_DBG("ts_users is user's primary group"); + return 1; + } + + if (0 != g_check_user_in_group(user, g_cfg->sec.ts_users, &ok)) + { + log_message(LOG_LEVEL_ERROR, "Cannot read group info! - login denied"); + return 0; + } + + if (ok) + { + return 1; + } + + log_message(LOG_LEVEL_INFO, "login denied for user %s", user); - if ((0 == g_strncmp(user, "root", 5)) && (0 == g_cfg->sec.allow_root)) - { - log_message(LOG_LEVEL_WARNING, - "ROOT login attempted, but root login is disabled"); return 0; - } - - if (0 == g_cfg->sec.ts_users_enable) - { - LOG_DBG("Terminal Server Users group is disabled, allowing authentication", - 1); - return 1; - } - - if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0)) - { - log_message(LOG_LEVEL_ERROR, "Cannot read user info! - login denied"); - return 0; - } - - if (g_cfg->sec.ts_users == gid) - { - LOG_DBG("ts_users is user's primary group"); - return 1; - } - - if (0 != g_check_user_in_group(user, g_cfg->sec.ts_users, &ok)) - { - log_message(LOG_LEVEL_ERROR, "Cannot read group info! - login denied"); - return 0; - } - - if (ok) - { - return 1; - } - - log_message(LOG_LEVEL_INFO, "login denied for user %s", user); - - return 0; } /******************************************************************************/ int DEFAULT_CC -access_login_mng_allowed(char* user) +access_login_mng_allowed(char *user) { - int gid; - int ok; + int gid; + int ok; + + if ((0 == g_strncmp(user, "root", 5)) && (0 == g_cfg->sec.allow_root)) + { + log_message(LOG_LEVEL_WARNING, + "[MNG] ROOT login attempted, but root login is disabled"); + return 0; + } + + if (0 == g_cfg->sec.ts_admins_enable) + { + LOG_DBG("[MNG] Terminal Server Admin group is disabled," + "allowing authentication", 1); + return 1; + } + + if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0)) + { + log_message(LOG_LEVEL_ERROR, "[MNG] Cannot read user info! - login denied"); + return 0; + } + + if (g_cfg->sec.ts_admins == gid) + { + LOG_DBG("[MNG] ts_users is user's primary group"); + return 1; + } + + if (0 != g_check_user_in_group(user, g_cfg->sec.ts_admins, &ok)) + { + log_message(LOG_LEVEL_ERROR, "[MNG] Cannot read group info! - login denied"); + return 0; + } + + if (ok) + { + return 1; + } + + log_message(LOG_LEVEL_INFO, "[MNG] login denied for user %s", user); - if ((0 == g_strncmp(user, "root", 5)) && (0 == g_cfg->sec.allow_root)) - { - log_message(LOG_LEVEL_WARNING, - "[MNG] ROOT login attempted, but root login is disabled"); return 0; - } - - if (0 == g_cfg->sec.ts_admins_enable) - { - LOG_DBG("[MNG] Terminal Server Admin group is disabled," - "allowing authentication",1); - return 1; - } - - if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0)) - { - log_message(LOG_LEVEL_ERROR, "[MNG] Cannot read user info! - login denied"); - return 0; - } - - if (g_cfg->sec.ts_admins == gid) - { - LOG_DBG("[MNG] ts_users is user's primary group"); - return 1; - } - - if (0 != g_check_user_in_group(user, g_cfg->sec.ts_admins, &ok)) - { - log_message(LOG_LEVEL_ERROR, "[MNG] Cannot read group info! - login denied"); - return 0; - } - - if (ok) - { - return 1; - } - - log_message(LOG_LEVEL_INFO, "[MNG] login denied for user %s", user); - - return 0; } diff --git a/sesman/access.h b/sesman/access.h index bad20540..d53c65ad 100644 --- a/sesman/access.h +++ b/sesman/access.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/auth.h b/sesman/auth.h index a6c5e7fa..09bec2e9 100644 --- a/sesman/auth.h +++ b/sesman/auth.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 10a42ef9..0f69f1f6 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -32,10 +32,10 @@ #include "rail.h" #include "xcommon.h" -static struct trans* g_lis_trans = 0; -static struct trans* g_con_trans = 0; -static struct trans* g_api_lis_trans = 0; -static struct trans* g_api_con_trans = 0; +static struct trans *g_lis_trans = 0; +static struct trans *g_con_trans = 0; +static struct trans *g_api_lis_trans = 0; +static struct trans *g_api_con_trans = 0; static struct chan_item g_chan_items[32]; static int g_num_chan_items = 0; static int g_cliprdr_index = -1; @@ -54,7 +54,7 @@ int g_rdpsnd_chan_id = -1; /* rdpsnd */ int g_rdpdr_chan_id = -1; /* rdpdr */ int g_rail_chan_id = -1; /* rail */ -char* g_exec_name; +char *g_exec_name; tbus g_exec_event; tbus g_exec_mutex; tbus g_exec_sem; @@ -63,97 +63,109 @@ int g_exec_pid = 0; /* data in struct trans::callback_data */ struct xrdp_api_data { - int chan_id; - char header[64]; - int flags; + int chan_id; + char header[64]; + int flags; }; /*****************************************************************************/ /* add data to chan_item, on its way to the client */ /* returns error */ static int APP_CC -add_data_to_chan_item(struct chan_item* chan_item, char* data, int size) +add_data_to_chan_item(struct chan_item *chan_item, char *data, int size) { - struct stream* s; - struct chan_out_data* cod; + struct stream *s; + struct chan_out_data *cod; - make_stream(s); - init_stream(s, size); - g_memcpy(s->data, data, size); - s->end = s->data + size; - cod = (struct chan_out_data*)g_malloc(sizeof(struct chan_out_data), 1); - cod->s = s; - if (chan_item->tail == 0) - { - chan_item->tail = cod; - chan_item->head = cod; - } - else - { - chan_item->tail->next = cod; - chan_item->tail = cod; - } - return 0; + make_stream(s); + init_stream(s, size); + g_memcpy(s->data, data, size); + s->end = s->data + size; + cod = (struct chan_out_data *)g_malloc(sizeof(struct chan_out_data), 1); + cod->s = s; + + if (chan_item->tail == 0) + { + chan_item->tail = cod; + chan_item->head = cod; + } + else + { + chan_item->tail->next = cod; + chan_item->tail = cod; + } + + return 0; } /*****************************************************************************/ /* returns error */ static int APP_CC -send_data_from_chan_item(struct chan_item* chan_item) +send_data_from_chan_item(struct chan_item *chan_item) { - struct stream* s; - struct chan_out_data* cod; - int bytes_left; - int size; - int chan_flags; - int error; + struct stream *s; + struct chan_out_data *cod; + int bytes_left; + int size; + int chan_flags; + int error; - if (chan_item->head == 0) - { - return 0; - } - cod = chan_item->head; - bytes_left = (int)(cod->s->end - cod->s->p); - size = MIN(1600, bytes_left); - chan_flags = 0; - if (cod->s->p == cod->s->data) - { - chan_flags |= 1; /* first */ - } - if (cod->s->p + size >= cod->s->end) - { - chan_flags |= 2; /* last */ - } - s = trans_get_out_s(g_con_trans, 8192); - out_uint32_le(s, 0); /* version */ - out_uint32_le(s, 8 + 8 + 2 + 2 + 2 + 4 + size); /* size */ - out_uint32_le(s, 8); /* msg id */ - out_uint32_le(s, 8 + 2 + 2 + 2 + 4 + size); /* size */ - out_uint16_le(s, chan_item->id); - out_uint16_le(s, chan_flags); - out_uint16_le(s, size); - out_uint32_le(s, cod->s->size); - out_uint8a(s, cod->s->p, size); - s_mark_end(s); - LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: -- " - "size %d chan_flags 0x%8.8x", size, chan_flags)); - error = trans_force_write(g_con_trans); - if (error != 0) - { - return 1; - } - cod->s->p += size; - if (cod->s->p >= cod->s->end) - { - free_stream(cod->s); - chan_item->head = chan_item->head->next; if (chan_item->head == 0) { - chan_item->tail = 0; + return 0; } - g_free(cod); - } - return 0; + + cod = chan_item->head; + bytes_left = (int)(cod->s->end - cod->s->p); + size = MIN(1600, bytes_left); + chan_flags = 0; + + if (cod->s->p == cod->s->data) + { + chan_flags |= 1; /* first */ + } + + if (cod->s->p + size >= cod->s->end) + { + chan_flags |= 2; /* last */ + } + + s = trans_get_out_s(g_con_trans, 8192); + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8 + 2 + 2 + 2 + 4 + size); /* size */ + out_uint32_le(s, 8); /* msg id */ + out_uint32_le(s, 8 + 2 + 2 + 2 + 4 + size); /* size */ + out_uint16_le(s, chan_item->id); + out_uint16_le(s, chan_flags); + out_uint16_le(s, size); + out_uint32_le(s, cod->s->size); + out_uint8a(s, cod->s->p, size); + s_mark_end(s); + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: -- " + "size %d chan_flags 0x%8.8x", size, chan_flags)); + error = trans_force_write(g_con_trans); + + if (error != 0) + { + return 1; + } + + cod->s->p += size; + + if (cod->s->p >= cod->s->end) + { + free_stream(cod->s); + chan_item->head = chan_item->head->next; + + if (chan_item->head == 0) + { + chan_item->tail = 0; + } + + g_free(cod); + } + + return 0; } /*****************************************************************************/ @@ -161,40 +173,44 @@ send_data_from_chan_item(struct chan_item* chan_item) static int APP_CC check_chan_items(void) { - int index; + int index; - for (index = 0; index < g_num_chan_items; index++) - { - if (g_chan_items[index].head != 0) + for (index = 0; index < g_num_chan_items; index++) { - send_data_from_chan_item(g_chan_items + index); + if (g_chan_items[index].head != 0) + { + send_data_from_chan_item(g_chan_items + index); + } } - } - return 0; + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -send_channel_data(int chan_id, char* data, int size) +send_channel_data(int chan_id, char *data, int size) { - int index; + int index; - LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: size %d", size)); - if (chan_id == -1) - { - return 1; - } - for (index = 0; index < g_num_chan_items; index++) - { - if (g_chan_items[index].id == chan_id) + LOGM((LOG_LEVEL_DEBUG, "chansrv::send_channel_data: size %d", size)); + + if (chan_id == -1) { - add_data_to_chan_item(g_chan_items + index, data, size); - check_chan_items(); - return 0; + return 1; } - } - return 1; + + for (index = 0; index < g_num_chan_items; index++) + { + if (g_chan_items[index].id == chan_id) + { + add_data_to_chan_item(g_chan_items + index, data, size); + check_chan_items(); + return 0; + } + } + + return 1; } /*****************************************************************************/ @@ -202,20 +218,22 @@ send_channel_data(int chan_id, char* data, int size) static int APP_CC send_init_response_message(void) { - struct stream * s = (struct stream *)NULL; + struct stream *s = (struct stream *)NULL; - LOGM((LOG_LEVEL_INFO, "send_init_response_message:")); - s = trans_get_out_s(g_con_trans, 8192); - if (s == 0) - { - return 1; - } - out_uint32_le(s, 0); /* version */ - out_uint32_le(s, 8 + 8); /* size */ - out_uint32_le(s, 2); /* msg id */ - out_uint32_le(s, 8); /* size */ - s_mark_end(s); - return trans_force_write(g_con_trans); + LOGM((LOG_LEVEL_INFO, "send_init_response_message:")); + s = trans_get_out_s(g_con_trans, 8192); + + if (s == 0) + { + return 1; + } + + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8); /* size */ + out_uint32_le(s, 2); /* msg id */ + out_uint32_le(s, 8); /* size */ + s_mark_end(s); + return trans_force_write(g_con_trans); } /*****************************************************************************/ @@ -223,20 +241,22 @@ send_init_response_message(void) static int APP_CC send_channel_setup_response_message(void) { - struct stream * s = (struct stream *)NULL; + struct stream *s = (struct stream *)NULL; - LOGM((LOG_LEVEL_DEBUG, "send_channel_setup_response_message:")); - s = trans_get_out_s(g_con_trans, 8192); - if (s == 0) - { - return 1; - } - out_uint32_le(s, 0); /* version */ - out_uint32_le(s, 8 + 8); /* size */ - out_uint32_le(s, 4); /* msg id */ - out_uint32_le(s, 8); /* size */ - s_mark_end(s); - return trans_force_write(g_con_trans); + LOGM((LOG_LEVEL_DEBUG, "send_channel_setup_response_message:")); + s = trans_get_out_s(g_con_trans, 8192); + + if (s == 0) + { + return 1; + } + + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8); /* size */ + out_uint32_le(s, 4); /* msg id */ + out_uint32_le(s, 8); /* size */ + s_mark_end(s); + return trans_force_write(g_con_trans); } /*****************************************************************************/ @@ -244,176 +264,192 @@ send_channel_setup_response_message(void) static int APP_CC send_channel_data_response_message(void) { - struct stream * s = (struct stream *)NULL; + struct stream *s = (struct stream *)NULL; - LOGM((LOG_LEVEL_DEBUG, "send_channel_data_response_message:")); - s = trans_get_out_s(g_con_trans, 8192); - if (s == 0) - { - return 1; - } - out_uint32_le(s, 0); /* version */ - out_uint32_le(s, 8 + 8); /* size */ - out_uint32_le(s, 6); /* msg id */ - out_uint32_le(s, 8); /* size */ - s_mark_end(s); - return trans_force_write(g_con_trans); + LOGM((LOG_LEVEL_DEBUG, "send_channel_data_response_message:")); + s = trans_get_out_s(g_con_trans, 8192); + + if (s == 0) + { + return 1; + } + + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8); /* size */ + out_uint32_le(s, 6); /* msg id */ + out_uint32_le(s, 8); /* size */ + s_mark_end(s); + return trans_force_write(g_con_trans); } /*****************************************************************************/ /* returns error */ static int APP_CC -process_message_init(struct stream* s) +process_message_init(struct stream *s) { - LOGM((LOG_LEVEL_DEBUG, "process_message_init:")); - return send_init_response_message(); + LOGM((LOG_LEVEL_DEBUG, "process_message_init:")); + return send_init_response_message(); } /*****************************************************************************/ /* returns error */ static int APP_CC -process_message_channel_setup(struct stream* s) +process_message_channel_setup(struct stream *s) { - int num_chans; - int index; - int rv; - struct chan_item* ci; + int num_chans; + int index; + int rv; + struct chan_item *ci; - g_num_chan_items = 0; - g_cliprdr_index = -1; - g_rdpsnd_index = -1; - g_rdpdr_index = -1; - g_rail_index = -1; - g_cliprdr_chan_id = -1; - g_rdpsnd_chan_id = -1; - g_rdpdr_chan_id = -1; - g_rail_chan_id = -1; - LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup:")); - in_uint16_le(s, num_chans); - LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup: num_chans %d", - num_chans)); - for (index = 0; index < num_chans; index++) - { - ci = &(g_chan_items[g_num_chan_items]); - g_memset(ci->name, 0, sizeof(ci->name)); - in_uint8a(s, ci->name, 8); - in_uint16_le(s, ci->id); - in_uint16_le(s, ci->flags); - LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup: chan name '%s' " - "id %d flags %8.8x", ci->name, ci->id, ci->flags)); - if (g_strcasecmp(ci->name, "cliprdr") == 0) + g_num_chan_items = 0; + g_cliprdr_index = -1; + g_rdpsnd_index = -1; + g_rdpdr_index = -1; + g_rail_index = -1; + g_cliprdr_chan_id = -1; + g_rdpsnd_chan_id = -1; + g_rdpdr_chan_id = -1; + g_rail_chan_id = -1; + LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup:")); + in_uint16_le(s, num_chans); + LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup: num_chans %d", + num_chans)); + + for (index = 0; index < num_chans; index++) { - g_cliprdr_index = g_num_chan_items; - g_cliprdr_chan_id = ci->id; + ci = &(g_chan_items[g_num_chan_items]); + g_memset(ci->name, 0, sizeof(ci->name)); + in_uint8a(s, ci->name, 8); + in_uint16_le(s, ci->id); + in_uint16_le(s, ci->flags); + LOGM((LOG_LEVEL_DEBUG, "process_message_channel_setup: chan name '%s' " + "id %d flags %8.8x", ci->name, ci->id, ci->flags)); + + if (g_strcasecmp(ci->name, "cliprdr") == 0) + { + g_cliprdr_index = g_num_chan_items; + g_cliprdr_chan_id = ci->id; + } + else if (g_strcasecmp(ci->name, "rdpsnd") == 0) + { + g_rdpsnd_index = g_num_chan_items; + g_rdpsnd_chan_id = ci->id; + } + else if (g_strcasecmp(ci->name, "rdpdr") == 0) + { + g_rdpdr_index = g_num_chan_items; + g_rdpdr_chan_id = ci->id; + } + else if (g_strcasecmp(ci->name, "rail") == 0) + { + g_rail_index = g_num_chan_items; + g_rail_chan_id = ci->id; + } + else + { + LOG(10, ("other %s", ci->name)); + } + + g_num_chan_items++; } - else if (g_strcasecmp(ci->name, "rdpsnd") == 0) + + rv = send_channel_setup_response_message(); + + if (g_cliprdr_index >= 0) { - g_rdpsnd_index = g_num_chan_items; - g_rdpsnd_chan_id = ci->id; + clipboard_init(); } - else if (g_strcasecmp(ci->name, "rdpdr") == 0) + + if (g_rdpsnd_index >= 0) { - g_rdpdr_index = g_num_chan_items; - g_rdpdr_chan_id = ci->id; + sound_init(); } - else if (g_strcasecmp(ci->name, "rail") == 0) + + if (g_rdpdr_index >= 0) { - g_rail_index = g_num_chan_items; - g_rail_chan_id = ci->id; + dev_redir_init(); } - else + + if (g_rail_index >= 0) { - LOG(10, ("other %s", ci->name)); + rail_init(); } - g_num_chan_items++; - } - rv = send_channel_setup_response_message(); - if (g_cliprdr_index >= 0) - { - clipboard_init(); - } - if (g_rdpsnd_index >= 0) - { - sound_init(); - } - if (g_rdpdr_index >= 0) - { - dev_redir_init(); - } - if (g_rail_index >= 0) - { - rail_init(); - } - return rv; + + return rv; } /*****************************************************************************/ /* returns error */ static int APP_CC -process_message_channel_data(struct stream* s) +process_message_channel_data(struct stream *s) { - int chan_id = 0; - int chan_flags = 0; - int rv = 0; - int length = 0; - int total_length = 0; - struct stream* ls; + int chan_id = 0; + int chan_flags = 0; + int rv = 0; + int length = 0; + int total_length = 0; + struct stream *ls; - in_uint16_le(s, chan_id); - in_uint16_le(s, chan_flags); - in_uint16_le(s, length); - in_uint32_le(s, total_length); - LOGM((LOG_LEVEL_DEBUG,"process_message_channel_data: chan_id %d " - "chan_flags %d", chan_id, chan_flags)); - LOG(10, ("process_message_channel_data")); - rv = send_channel_data_response_message(); - if (rv == 0) - { - if (chan_id == g_cliprdr_chan_id) + in_uint16_le(s, chan_id); + in_uint16_le(s, chan_flags); + in_uint16_le(s, length); + in_uint32_le(s, total_length); + LOGM((LOG_LEVEL_DEBUG, "process_message_channel_data: chan_id %d " + "chan_flags %d", chan_id, chan_flags)); + LOG(10, ("process_message_channel_data")); + rv = send_channel_data_response_message(); + + if (rv == 0) { - rv = clipboard_data_in(s, chan_id, chan_flags, length, total_length); + if (chan_id == g_cliprdr_chan_id) + { + rv = clipboard_data_in(s, chan_id, chan_flags, length, total_length); + } + else if (chan_id == g_rdpsnd_chan_id) + { + rv = sound_data_in(s, chan_id, chan_flags, length, total_length); + } + else if (chan_id == g_rdpdr_chan_id) + { + rv = dev_redir_data_in(s, chan_id, chan_flags, length, total_length); + } + else if (chan_id == g_rail_chan_id) + { + rv = rail_data_in(s, chan_id, chan_flags, length, total_length); + } + else if (chan_id == ((struct xrdp_api_data *) + (g_api_con_trans->callback_data))->chan_id) + { + LOG(10, ("process_message_channel_data length %d total_length %d " + "chan_flags 0x%8.8x", length, total_length, chan_flags)); + ls = g_api_con_trans->out_s; + + if (chan_flags & 1) /* first */ + { + init_stream(ls, total_length); + } + + out_uint8a(ls, s->p, length); + + if (chan_flags & 2) /* last */ + { + s_mark_end(ls); + trans_force_write(g_api_con_trans); + } + } } - else if (chan_id == g_rdpsnd_chan_id) - { - rv = sound_data_in(s, chan_id, chan_flags, length, total_length); - } - else if (chan_id == g_rdpdr_chan_id) - { - rv = dev_redir_data_in(s, chan_id, chan_flags, length, total_length); - } - else if (chan_id == g_rail_chan_id) - { - rv = rail_data_in(s, chan_id, chan_flags, length, total_length); - } - else if (chan_id == ((struct xrdp_api_data*) - (g_api_con_trans->callback_data))->chan_id) - { - LOG(10, ("process_message_channel_data length %d total_length %d " - "chan_flags 0x%8.8x", length, total_length, chan_flags)); - ls = g_api_con_trans->out_s; - if (chan_flags & 1) /* first */ - { - init_stream(ls, total_length); - } - out_uint8a(ls, s->p, length); - if (chan_flags & 2) /* last */ - { - s_mark_end(ls); - trans_force_write(g_api_con_trans); - } - } - } - return rv; + + return rv; } /*****************************************************************************/ /* returns error */ static int APP_CC -process_message_channel_data_response(struct stream* s) +process_message_channel_data_response(struct stream *s) { - LOG(10, ("process_message_channel_data_response:")); - check_chan_items(); - return 0; + LOG(10, ("process_message_channel_data_response:")); + check_chan_items(); + return 0; } /*****************************************************************************/ @@ -421,680 +457,752 @@ process_message_channel_data_response(struct stream* s) static int APP_CC process_message(void) { - struct stream * s = (struct stream *)NULL; - int size = 0; - int id = 0; - int rv = 0; - char* next_msg = (char *)NULL; + struct stream *s = (struct stream *)NULL; + int size = 0; + int id = 0; + int rv = 0; + char *next_msg = (char *)NULL; - if (g_con_trans == 0) - { - return 1; - } - s = trans_get_in_s(g_con_trans); - if (s == 0) - { - return 1; - } - rv = 0; - while (s_check_rem(s, 8)) - { - next_msg = s->p; + if (g_con_trans == 0) + { + return 1; + } + + s = trans_get_in_s(g_con_trans); + + if (s == 0) + { + return 1; + } + + rv = 0; + + while (s_check_rem(s, 8)) + { + next_msg = s->p; + in_uint32_le(s, id); + in_uint32_le(s, size); + next_msg += size; + + switch (id) + { + case 1: /* init */ + rv = process_message_init(s); + break; + case 3: /* channel setup */ + rv = process_message_channel_setup(s); + break; + case 5: /* channel data */ + rv = process_message_channel_data(s); + break; + case 7: /* channel data response */ + rv = process_message_channel_data_response(s); + break; + default: + LOGM((LOG_LEVEL_ERROR, "process_message: error in process_message ", + "unknown msg %d", id)); + break; + } + + if (rv != 0) + { + break; + } + + s->p = next_msg; + } + + return rv; +} + +/*****************************************************************************/ +/* returns error */ +int DEFAULT_CC +my_trans_data_in(struct trans *trans) +{ + struct stream *s = (struct stream *)NULL; + int id = 0; + int size = 0; + int error = 0; + + if (trans == 0) + { + return 0; + } + + if (trans != g_con_trans) + { + return 1; + } + + LOGM((LOG_LEVEL_DEBUG, "my_trans_data_in:")); + s = trans_get_in_s(trans); in_uint32_le(s, id); in_uint32_le(s, size); - next_msg += size; - switch (id) + error = trans_force_read(trans, size - 8); + + if (error == 0) { - case 1: /* init */ - rv = process_message_init(s); - break; - case 3: /* channel setup */ - rv = process_message_channel_setup(s); - break; - case 5: /* channel data */ - rv = process_message_channel_data(s); - break; - case 7: /* channel data response */ - rv = process_message_channel_data_response(s); - break; - default: - LOGM((LOG_LEVEL_ERROR, "process_message: error in process_message ", - "unknown msg %d", id)); - break; + /* here, the entire message block is read in, process it */ + error = process_message(); } - if (rv != 0) - { - break; - } - s->p = next_msg; - } - return rv; + + return error; } /*****************************************************************************/ /* returns error */ int DEFAULT_CC -my_trans_data_in(struct trans* trans) +my_api_trans_data_in(struct trans *trans) { - struct stream * s = (struct stream *)NULL; - int id = 0; - int size = 0; - int error = 0; + struct stream *s; + int error; + struct xrdp_api_data *ad; - if (trans == 0) - { - return 0; - } - if (trans != g_con_trans) - { - return 1; - } - LOGM((LOG_LEVEL_DEBUG, "my_trans_data_in:")); - s = trans_get_in_s(trans); - in_uint32_le(s, id); - in_uint32_le(s, size); - error = trans_force_read(trans, size - 8); - if (error == 0) - { - /* here, the entire message block is read in, process it */ - error = process_message(); - } - return error; -} + LOG(10, ("my_api_trans_data_in:")); -/*****************************************************************************/ -/* returns error */ -int DEFAULT_CC -my_api_trans_data_in(struct trans* trans) -{ - struct stream* s; - int error; - struct xrdp_api_data* ad; - - LOG(10, ("my_api_trans_data_in:")); - if (trans == 0) - { - return 0; - } - if (trans != g_api_con_trans) - { - return 1; - } - LOGM((LOG_LEVEL_DEBUG, "my_api_trans_data_in:")); - s = trans_get_in_s(trans); - error = g_tcp_recv(trans->sck, s->data, 8192, 0); - if (error > 0) - { - LOG(10, ("my_api_trans_data_in: got data %d", error)); - ad = (struct xrdp_api_data*)(trans->callback_data); - if (send_channel_data(ad->chan_id, s->data, error) != 0) + if (trans == 0) { - LOG(0, ("my_api_trans_data_in: send_channel_data failed")); + return 0; } - } - else - { - LOG(10, ("my_api_trans_data_in: g_tcp_recv failed, or disconnected")); - return 1; - } - return 0; + + if (trans != g_api_con_trans) + { + return 1; + } + + LOGM((LOG_LEVEL_DEBUG, "my_api_trans_data_in:")); + s = trans_get_in_s(trans); + error = g_tcp_recv(trans->sck, s->data, 8192, 0); + + if (error > 0) + { + LOG(10, ("my_api_trans_data_in: got data %d", error)); + ad = (struct xrdp_api_data *)(trans->callback_data); + + if (send_channel_data(ad->chan_id, s->data, error) != 0) + { + LOG(0, ("my_api_trans_data_in: send_channel_data failed")); + } + } + else + { + LOG(10, ("my_api_trans_data_in: g_tcp_recv failed, or disconnected")); + return 1; + } + + return 0; } /*****************************************************************************/ int DEFAULT_CC -my_trans_conn_in(struct trans* trans, struct trans* new_trans) +my_trans_conn_in(struct trans *trans, struct trans *new_trans) { - if (trans == 0) - { - return 1; - } - if (trans != g_lis_trans) - { - return 1; - } - if (g_con_trans != 0) /* if already set, error */ - { - return 1; - } - if (new_trans == 0) - { - return 1; - } - LOGM((LOG_LEVEL_DEBUG, "my_trans_conn_in:")); - g_con_trans = new_trans; - g_con_trans->trans_data_in = my_trans_data_in; - g_con_trans->header_size = 8; - /* stop listening */ - trans_delete(g_lis_trans); - g_lis_trans = 0; - return 0; + if (trans == 0) + { + return 1; + } + + if (trans != g_lis_trans) + { + return 1; + } + + if (g_con_trans != 0) /* if already set, error */ + { + return 1; + } + + if (new_trans == 0) + { + return 1; + } + + LOGM((LOG_LEVEL_DEBUG, "my_trans_conn_in:")); + g_con_trans = new_trans; + g_con_trans->trans_data_in = my_trans_data_in; + g_con_trans->header_size = 8; + /* stop listening */ + trans_delete(g_lis_trans); + g_lis_trans = 0; + return 0; } /*****************************************************************************/ int DEFAULT_CC -my_api_trans_conn_in(struct trans* trans, struct trans* new_trans) +my_api_trans_conn_in(struct trans *trans, struct trans *new_trans) { - struct xrdp_api_data* ad; - int error; - int index; - int found; - struct stream* s; + struct xrdp_api_data *ad; + int error; + int index; + int found; + struct stream *s; - if (trans == 0) - { - return 1; - } - if (trans != g_api_lis_trans) - { - return 1; - } - if (new_trans == 0) - { - return 1; - } - LOGM((LOG_LEVEL_DEBUG, "my_api_trans_conn_in:")); + if (trans == 0) + { + return 1; + } - LOG(10, ("my_api_trans_conn_in: got incoming")); + if (trans != g_api_lis_trans) + { + return 1; + } - s = trans_get_in_s(new_trans); - s->end = s->data; - error = trans_force_read(new_trans, 64); - if (error != 0) - { - LOG(0, ("my_api_trans_conn_in: trans_force_read failed")); - trans_delete(new_trans); - } - s->end = s->data; + if (new_trans == 0) + { + return 1; + } - ad = (struct xrdp_api_data*)g_malloc(sizeof(struct xrdp_api_data), 1); + LOGM((LOG_LEVEL_DEBUG, "my_api_trans_conn_in:")); - g_memcpy(ad->header, s->data, 64); + LOG(10, ("my_api_trans_conn_in: got incoming")); - ad->flags = GGET_UINT32(ad->header, 16); + s = trans_get_in_s(new_trans); + s->end = s->data; + error = trans_force_read(new_trans, 64); + + if (error != 0) + { + LOG(0, ("my_api_trans_conn_in: trans_force_read failed")); + trans_delete(new_trans); + } + + s->end = s->data; + + ad = (struct xrdp_api_data *)g_malloc(sizeof(struct xrdp_api_data), 1); + + g_memcpy(ad->header, s->data, 64); + + ad->flags = GGET_UINT32(ad->header, 16); - found = 0; - if (ad->flags | 1) /* WTS_CHANNEL_OPTION_DYNAMIC */ - { - /* TODO */ found = 0; - } - else - { - for (index = 0; index < g_num_chan_items; index++) + + if (ad->flags | 1) /* WTS_CHANNEL_OPTION_DYNAMIC */ { - LOG(10, (" %s %s", ad->header, g_chan_items[index].name)); - if (g_strcasecmp(ad->header, g_chan_items[index].name) == 0) - { - LOG(10, ("my_api_trans_conn_in: found it at %d", index)); - ad->chan_id = g_chan_items[index].id; - found = 1; - break; - } + /* TODO */ + found = 0; } - } - LOG(10, ("my_api_trans_conn_in: found %d", found)); - if (!found) - { - ad->chan_id = -1; - } + else + { + for (index = 0; index < g_num_chan_items; index++) + { + LOG(10, (" %s %s", ad->header, g_chan_items[index].name)); - new_trans->callback_data = ad; + if (g_strcasecmp(ad->header, g_chan_items[index].name) == 0) + { + LOG(10, ("my_api_trans_conn_in: found it at %d", index)); + ad->chan_id = g_chan_items[index].id; + found = 1; + break; + } + } + } - trans_delete(g_api_con_trans); - g_api_con_trans = new_trans; - g_api_con_trans->trans_data_in = my_api_trans_data_in; - g_api_con_trans->header_size = 0; + LOG(10, ("my_api_trans_conn_in: found %d", found)); - return 0; + if (!found) + { + ad->chan_id = -1; + } + + new_trans->callback_data = ad; + + trans_delete(g_api_con_trans); + g_api_con_trans = new_trans; + g_api_con_trans->trans_data_in = my_api_trans_data_in; + g_api_con_trans->header_size = 0; + + return 0; } /*****************************************************************************/ static int APP_CC setup_listen(void) { - char port[256]; - int error = 0; + char port[256]; + int error = 0; - if (g_lis_trans != 0) - { - trans_delete(g_lis_trans); - } - if (g_use_unix_socket) - { - g_lis_trans = trans_create(2, 8192, 8192); - g_snprintf(port, 255, "/tmp/.xrdp/xrdp_chansrv_socket_%d", - 7200 + g_display_num); - } - else - { - g_lis_trans = trans_create(1, 8192, 8192); - g_snprintf(port, 255, "%d", 7200 + g_display_num); - } - g_lis_trans->trans_conn_in = my_trans_conn_in; - error = trans_listen(g_lis_trans, port); - if (error != 0) - { - LOGM((LOG_LEVEL_ERROR, "setup_listen: trans_listen failed for port %s", - port)); - return 1; - } - return 0; + if (g_lis_trans != 0) + { + trans_delete(g_lis_trans); + } + + if (g_use_unix_socket) + { + g_lis_trans = trans_create(2, 8192, 8192); + g_snprintf(port, 255, "/tmp/.xrdp/xrdp_chansrv_socket_%d", + 7200 + g_display_num); + } + else + { + g_lis_trans = trans_create(1, 8192, 8192); + g_snprintf(port, 255, "%d", 7200 + g_display_num); + } + + g_lis_trans->trans_conn_in = my_trans_conn_in; + error = trans_listen(g_lis_trans, port); + + if (error != 0) + { + LOGM((LOG_LEVEL_ERROR, "setup_listen: trans_listen failed for port %s", + port)); + return 1; + } + + return 0; } /*****************************************************************************/ static int APP_CC setup_api_listen(void) { - char port[256]; - int error = 0; + char port[256]; + int error = 0; - g_api_lis_trans = trans_create(2, 8192, 8192); - g_snprintf(port, 255, "/tmp/.xrdp/xrdpapi_%d", g_display_num); - g_api_lis_trans->trans_conn_in = my_api_trans_conn_in; - error = trans_listen(g_api_lis_trans, port); - if (error != 0) - { - LOGM((LOG_LEVEL_ERROR, "setup_api_listen: trans_listen failed for port %s", - port)); - return 1; - } - return 0; + g_api_lis_trans = trans_create(2, 8192, 8192); + g_snprintf(port, 255, "/tmp/.xrdp/xrdpapi_%d", g_display_num); + g_api_lis_trans->trans_conn_in = my_api_trans_conn_in; + error = trans_listen(g_api_lis_trans, port); + + if (error != 0) + { + LOGM((LOG_LEVEL_ERROR, "setup_api_listen: trans_listen failed for port %s", + port)); + return 1; + } + + return 0; } /*****************************************************************************/ THREAD_RV THREAD_CC -channel_thread_loop(void* in_val) +channel_thread_loop(void *in_val) { - tbus objs[32]; - int num_objs; - int timeout; - int error; - THREAD_RV rv; + tbus objs[32]; + int num_objs; + int timeout; + int error; + THREAD_RV rv; - LOGM((LOG_LEVEL_INFO, "channel_thread_loop: thread start")); - rv = 0; - setup_api_listen(); - error = setup_listen(); - if (error == 0) - { - timeout = -1; - num_objs = 0; - objs[num_objs] = g_term_event; - num_objs++; - trans_get_wait_objs(g_lis_trans, objs, &num_objs); - trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); - while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) + LOGM((LOG_LEVEL_INFO, "channel_thread_loop: thread start")); + rv = 0; + setup_api_listen(); + error = setup_listen(); + + if (error == 0) { - if (g_is_wait_obj_set(g_term_event)) - { - LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set")); - clipboard_deinit(); - sound_deinit(); - dev_redir_deinit(); - rail_deinit(); - break; - } - if (g_lis_trans != 0) - { - if (trans_check_wait_objs(g_lis_trans) != 0) - { - LOGM((LOG_LEVEL_INFO, "channel_thread_loop: " - "trans_check_wait_objs error")); - } - } - if (g_con_trans != 0) - { - if (trans_check_wait_objs(g_con_trans) != 0) - { - LOGM((LOG_LEVEL_INFO, "channel_thread_loop: " - "trans_check_wait_objs error resetting")); - clipboard_deinit(); - sound_deinit(); - dev_redir_deinit(); - rail_deinit(); - /* delete g_con_trans */ - trans_delete(g_con_trans); - g_con_trans = 0; - /* create new listener */ - error = setup_listen(); - if (error != 0) - { - break; - } - } - } - if (g_api_lis_trans != 0) - { - if (trans_check_wait_objs(g_api_lis_trans) != 0) - { - LOG(0, ("channel_thread_loop: trans_check_wait_objs failed")); - } - } + timeout = -1; + num_objs = 0; + objs[num_objs] = g_term_event; + num_objs++; + trans_get_wait_objs(g_lis_trans, objs, &num_objs); + trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); - LOG(10, ("0 %p", g_api_con_trans)); - if (g_api_con_trans != 0) - { - LOG(10, ("1 %p %d", g_api_con_trans, g_tcp_can_recv(g_api_con_trans->sck, 0))); - if (trans_check_wait_objs(g_api_con_trans) != 0) + while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) { - LOG(10, ("channel_thread_loop: trans_check_wait_objs failed, " - "or disconnected")); - g_free(g_api_con_trans->callback_data); - trans_delete(g_api_con_trans); - g_api_con_trans = 0; - } - } + if (g_is_wait_obj_set(g_term_event)) + { + LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set")); + clipboard_deinit(); + sound_deinit(); + dev_redir_deinit(); + rail_deinit(); + break; + } - xcommon_check_wait_objs(); - sound_check_wait_objs(); - dev_redir_check_wait_objs(); - timeout = -1; - num_objs = 0; - objs[num_objs] = g_term_event; - num_objs++; - trans_get_wait_objs(g_lis_trans, objs, &num_objs); - trans_get_wait_objs(g_con_trans, objs, &num_objs); - trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); - trans_get_wait_objs(g_api_con_trans, objs, &num_objs); - xcommon_get_wait_objs(objs, &num_objs, &timeout); - sound_get_wait_objs(objs, &num_objs, &timeout); - dev_redir_get_wait_objs(objs, &num_objs, &timeout); + if (g_lis_trans != 0) + { + if (trans_check_wait_objs(g_lis_trans) != 0) + { + LOGM((LOG_LEVEL_INFO, "channel_thread_loop: " + "trans_check_wait_objs error")); + } + } + + if (g_con_trans != 0) + { + if (trans_check_wait_objs(g_con_trans) != 0) + { + LOGM((LOG_LEVEL_INFO, "channel_thread_loop: " + "trans_check_wait_objs error resetting")); + clipboard_deinit(); + sound_deinit(); + dev_redir_deinit(); + rail_deinit(); + /* delete g_con_trans */ + trans_delete(g_con_trans); + g_con_trans = 0; + /* create new listener */ + error = setup_listen(); + + if (error != 0) + { + break; + } + } + } + + if (g_api_lis_trans != 0) + { + if (trans_check_wait_objs(g_api_lis_trans) != 0) + { + LOG(0, ("channel_thread_loop: trans_check_wait_objs failed")); + } + } + + LOG(10, ("0 %p", g_api_con_trans)); + + if (g_api_con_trans != 0) + { + LOG(10, ("1 %p %d", g_api_con_trans, g_tcp_can_recv(g_api_con_trans->sck, 0))); + + if (trans_check_wait_objs(g_api_con_trans) != 0) + { + LOG(10, ("channel_thread_loop: trans_check_wait_objs failed, " + "or disconnected")); + g_free(g_api_con_trans->callback_data); + trans_delete(g_api_con_trans); + g_api_con_trans = 0; + } + } + + xcommon_check_wait_objs(); + sound_check_wait_objs(); + dev_redir_check_wait_objs(); + timeout = -1; + num_objs = 0; + objs[num_objs] = g_term_event; + num_objs++; + trans_get_wait_objs(g_lis_trans, objs, &num_objs); + trans_get_wait_objs(g_con_trans, objs, &num_objs); + trans_get_wait_objs(g_api_lis_trans, objs, &num_objs); + trans_get_wait_objs(g_api_con_trans, objs, &num_objs); + xcommon_get_wait_objs(objs, &num_objs, &timeout); + sound_get_wait_objs(objs, &num_objs, &timeout); + dev_redir_get_wait_objs(objs, &num_objs, &timeout); + } } - } - trans_delete(g_lis_trans); - g_lis_trans = 0; - trans_delete(g_con_trans); - g_con_trans = 0; - trans_delete(g_api_lis_trans); - g_api_lis_trans = 0; - trans_delete(g_api_con_trans); - g_api_con_trans = 0; - LOGM((LOG_LEVEL_INFO, "channel_thread_loop: thread stop")); - g_set_wait_obj(g_thread_done_event); - return rv; + + trans_delete(g_lis_trans); + g_lis_trans = 0; + trans_delete(g_con_trans); + g_con_trans = 0; + trans_delete(g_api_lis_trans); + g_api_lis_trans = 0; + trans_delete(g_api_con_trans); + g_api_con_trans = 0; + LOGM((LOG_LEVEL_INFO, "channel_thread_loop: thread stop")); + g_set_wait_obj(g_thread_done_event); + return rv; } /*****************************************************************************/ void DEFAULT_CC term_signal_handler(int sig) { - LOGM((LOG_LEVEL_INFO, "term_signal_handler: got signal %d", sig)); - g_set_wait_obj(g_term_event); + LOGM((LOG_LEVEL_INFO, "term_signal_handler: got signal %d", sig)); + g_set_wait_obj(g_term_event); } /*****************************************************************************/ void DEFAULT_CC nil_signal_handler(int sig) { - LOGM((LOG_LEVEL_INFO, "nil_signal_handler: got signal %d", sig)); + LOGM((LOG_LEVEL_INFO, "nil_signal_handler: got signal %d", sig)); } /*****************************************************************************/ void DEFAULT_CC child_signal_handler(int sig) { - int i1; + int i1; - LOG(10, ("child_signal_handler:")); - do - { - i1 = g_waitchild(); - if (i1 == g_exec_pid) + LOG(10, ("child_signal_handler:")); + + do { - LOG(0, ("child_signal_handler: found pid %d", i1)); - //shutdownx(); + i1 = g_waitchild(); + + if (i1 == g_exec_pid) + { + LOG(0, ("child_signal_handler: found pid %d", i1)); + //shutdownx(); + } + + LOG(10, (" %d", i1)); } - LOG(10, (" %d", i1)); - } while (i1 >= 0); + while (i1 >= 0); } /*****************************************************************************/ static int APP_CC -get_display_num_from_display(char* display_text) +get_display_num_from_display(char *display_text) { - int index; - int mode; - int host_index; - int disp_index; - int scre_index; - char host[256]; - char disp[256]; - char scre[256]; + int index; + int mode; + int host_index; + int disp_index; + int scre_index; + char host[256]; + char disp[256]; + char scre[256]; - g_memset(host, 0, 256); - g_memset(disp, 0, 256); - g_memset(scre, 0, 256); + g_memset(host, 0, 256); + g_memset(disp, 0, 256); + g_memset(scre, 0, 256); - index = 0; - host_index = 0; - disp_index = 0; - scre_index = 0; - mode = 0; - while (display_text[index] != 0) - { - if (display_text[index] == ':') + index = 0; + host_index = 0; + disp_index = 0; + scre_index = 0; + mode = 0; + + while (display_text[index] != 0) { - mode = 1; + if (display_text[index] == ':') + { + mode = 1; + } + else if (display_text[index] == '.') + { + mode = 2; + } + else if (mode == 0) + { + host[host_index] = display_text[index]; + host_index++; + } + else if (mode == 1) + { + disp[disp_index] = display_text[index]; + disp_index++; + } + else if (mode == 2) + { + scre[scre_index] = display_text[index]; + scre_index++; + } + + index++; } - else if (display_text[index] == '.') - { - mode = 2; - } - else if (mode == 0) - { - host[host_index] = display_text[index]; - host_index++; - } - else if (mode == 1) - { - disp[disp_index] = display_text[index]; - disp_index++; - } - else if (mode == 2) - { - scre[scre_index] = display_text[index]; - scre_index++; - } - index++; - } - host[host_index] = 0; - disp[disp_index] = 0; - scre[scre_index] = 0; - g_display_num = g_atoi(disp); - return 0; + + host[host_index] = 0; + disp[disp_index] = 0; + scre[scre_index] = 0; + g_display_num = g_atoi(disp); + return 0; } /*****************************************************************************/ int APP_CC main_cleanup(void) { - g_delete_wait_obj(g_term_event); - g_delete_wait_obj(g_thread_done_event); - g_delete_wait_obj(g_exec_event); - tc_mutex_delete(g_exec_mutex); - g_deinit(); /* os_calls */ - return 0; + g_delete_wait_obj(g_term_event); + g_delete_wait_obj(g_thread_done_event); + g_delete_wait_obj(g_exec_event); + tc_mutex_delete(g_exec_mutex); + g_deinit(); /* os_calls */ + return 0; } /*****************************************************************************/ static int APP_CC read_ini(void) { - char filename[256]; - struct list* names; - struct list* values; - char* name; - char* value; - int index; + char filename[256]; + struct list *names; + struct list *values; + char *name; + char *value; + int index; - g_memset(filename,0,(sizeof(char) * 256)); - names = list_create(); - names->auto_free = 1; - values = list_create(); - values->auto_free = 1; - g_use_unix_socket = 0; - g_snprintf(filename, 255, "%s/sesman.ini", XRDP_CFG_PATH); - if (file_by_name_read_section(filename, "Globals", names, values) == 0) - { - for (index = 0; index < names->count; index++) + g_memset(filename, 0, (sizeof(char) * 256)); + names = list_create(); + names->auto_free = 1; + values = list_create(); + values->auto_free = 1; + g_use_unix_socket = 0; + g_snprintf(filename, 255, "%s/sesman.ini", XRDP_CFG_PATH); + + if (file_by_name_read_section(filename, "Globals", names, values) == 0) { - name = (char*)list_get_item(names, index); - value = (char*)list_get_item(values, index); - if (g_strcasecmp(name, "ListenAddress") == 0) - { - if (g_strcasecmp(value, "127.0.0.1") == 0) + for (index = 0; index < names->count; index++) { - g_use_unix_socket = 1; + name = (char *)list_get_item(names, index); + value = (char *)list_get_item(values, index); + + if (g_strcasecmp(name, "ListenAddress") == 0) + { + if (g_strcasecmp(value, "127.0.0.1") == 0) + { + g_use_unix_socket = 1; + } + } } - } } - } - list_delete(names); - list_delete(values); - return 0; + + list_delete(names); + list_delete(values); + return 0; } /*****************************************************************************/ static int APP_CC run_exec(void) { - int pid; + int pid; - LOG(10, ("run_exec:")); - pid = g_fork(); - if (pid == 0) - { - trans_delete(g_con_trans); - g_close_wait_obj(g_term_event); - g_close_wait_obj(g_thread_done_event); - g_close_wait_obj(g_exec_event); - tc_mutex_delete(g_exec_mutex); - tc_sem_delete(g_exec_sem); - g_execlp3(g_exec_name, g_exec_name, 0); - g_exit(0); - } - g_exec_pid = pid; - tc_sem_inc(g_exec_sem); + LOG(10, ("run_exec:")); + pid = g_fork(); - return 0; + if (pid == 0) + { + trans_delete(g_con_trans); + g_close_wait_obj(g_term_event); + g_close_wait_obj(g_thread_done_event); + g_close_wait_obj(g_exec_event); + tc_mutex_delete(g_exec_mutex); + tc_sem_delete(g_exec_sem); + g_execlp3(g_exec_name, g_exec_name, 0); + g_exit(0); + } + + g_exec_pid = pid; + tc_sem_inc(g_exec_sem); + + return 0; } /*****************************************************************************/ int DEFAULT_CC -main(int argc, char** argv) +main(int argc, char **argv) { - tbus waiters[4]; - int pid = 0; - char text[256]; - char* home_text; - char* display_text; - char log_file[256]; - enum logReturns error; - struct log_config logconfig; + tbus waiters[4]; + int pid = 0; + char text[256]; + char *home_text; + char *display_text; + char log_file[256]; + enum logReturns error; + struct log_config logconfig; - g_init("xrdp-chansrv"); /* os_calls */ + g_init("xrdp-chansrv"); /* os_calls */ - home_text = g_getenv("HOME"); - if (home_text == 0) - { - g_writeln("error reading HOME environment variable"); + home_text = g_getenv("HOME"); + + if (home_text == 0) + { + g_writeln("error reading HOME environment variable"); + g_deinit(); + return 1; + } + + read_ini(); + pid = g_getpid(); + + /* starting logging subsystem */ + g_memset(&logconfig, 0, sizeof(struct log_config)); + logconfig.program_name = "XRDP-Chansrv"; + g_snprintf(log_file, 255, "%s/xrdp-chansrv.log", home_text); + g_writeln("chansrv::main: using log file [%s]", log_file); + + if (g_file_exist(log_file)) + { + g_file_delete(log_file); + } + + logconfig.log_file = log_file; + logconfig.fd = -1; + logconfig.log_level = LOG_LEVEL_ERROR; + logconfig.enable_syslog = 0; + logconfig.syslog_level = 0; + error = log_start_from_param(&logconfig); + + if (error != LOG_STARTUP_OK) + { + switch (error) + { + case LOG_ERROR_MALLOC: + g_writeln("error on malloc. cannot start logging. quitting."); + break; + case LOG_ERROR_FILE_OPEN: + g_writeln("error opening log file [%s]. quitting.", + getLogFile(text, 255)); + break; + default: + g_writeln("log_start error"); + break; + } + + g_deinit(); + return 1; + } + + LOGM((LOG_LEVEL_ALWAYS, "main: app started pid %d(0x%8.8x)", pid, pid)); + /* set up signal handler */ + g_signal_kill(term_signal_handler); /* SIGKILL */ + g_signal_terminate(term_signal_handler); /* SIGTERM */ + g_signal_user_interrupt(term_signal_handler); /* SIGINT */ + g_signal_pipe(nil_signal_handler); /* SIGPIPE */ + g_signal_child_stop(child_signal_handler); /* SIGCHLD */ + display_text = g_getenv("DISPLAY"); + LOGM((LOG_LEVEL_INFO, "main: DISPLAY env var set to %s", display_text)); + get_display_num_from_display(display_text); + + if (g_display_num == 0) + { + LOGM((LOG_LEVEL_ERROR, "main: error, display is zero")); + g_deinit(); + return 1; + } + + LOGM((LOG_LEVEL_INFO, "main: using DISPLAY %d", g_display_num)); + g_snprintf(text, 255, "xrdp_chansrv_%8.8x_main_term", pid); + g_term_event = g_create_wait_obj(text); + g_snprintf(text, 255, "xrdp_chansrv_%8.8x_thread_done", pid); + g_thread_done_event = g_create_wait_obj(text); + g_snprintf(text, 255, "xrdp_chansrv_%8.8x_exec", pid); + g_exec_event = g_create_wait_obj(text); + g_exec_mutex = tc_mutex_create(); + g_exec_sem = tc_sem_create(0); + tc_thread_create(channel_thread_loop, 0); + + while (g_term_event > 0 && !g_is_wait_obj_set(g_term_event)) + { + waiters[0] = g_term_event; + waiters[1] = g_exec_event; + + if (g_obj_wait(waiters, 2, 0, 0, 0) != 0) + { + LOGM((LOG_LEVEL_ERROR, "main: error, g_obj_wait failed")); + break; + } + + if (g_is_wait_obj_set(g_term_event)) + { + break; + } + + if (g_is_wait_obj_set(g_exec_event)) + { + g_reset_wait_obj(g_exec_event); + run_exec(); + } + } + + while (g_thread_done_event > 0 && !g_is_wait_obj_set(g_thread_done_event)) + { + /* wait for thread to exit */ + if (g_obj_wait(&g_thread_done_event, 1, 0, 0, 0) != 0) + { + LOGM((LOG_LEVEL_ERROR, "main: error, g_obj_wait failed")); + break; + } + } + + /* cleanup */ + main_cleanup(); + LOGM((LOG_LEVEL_INFO, "main: app exiting pid %d(0x%8.8x)", pid, pid)); g_deinit(); - return 1; - } - - read_ini(); - pid = g_getpid(); - - /* starting logging subsystem */ - g_memset(&logconfig, 0, sizeof(struct log_config)); - logconfig.program_name = "XRDP-Chansrv"; - g_snprintf(log_file, 255, "%s/xrdp-chansrv.log", home_text); - g_writeln("chansrv::main: using log file [%s]", log_file); - if (g_file_exist(log_file)) - { - g_file_delete(log_file); - } - logconfig.log_file = log_file; - logconfig.fd = -1; - logconfig.log_level = LOG_LEVEL_ERROR; - logconfig.enable_syslog = 0; - logconfig.syslog_level = 0; - error = log_start_from_param(&logconfig); - if (error != LOG_STARTUP_OK) - { - switch (error) - { - case LOG_ERROR_MALLOC: - g_writeln("error on malloc. cannot start logging. quitting."); - break; - case LOG_ERROR_FILE_OPEN: - g_writeln("error opening log file [%s]. quitting.", - getLogFile(text, 255)); - break; - default: - g_writeln("log_start error"); - break; - } - g_deinit(); - return 1; - } - LOGM((LOG_LEVEL_ALWAYS, "main: app started pid %d(0x%8.8x)", pid, pid)); - /* set up signal handler */ - g_signal_kill(term_signal_handler); /* SIGKILL */ - g_signal_terminate(term_signal_handler); /* SIGTERM */ - g_signal_user_interrupt(term_signal_handler); /* SIGINT */ - g_signal_pipe(nil_signal_handler); /* SIGPIPE */ - g_signal_child_stop(child_signal_handler); /* SIGCHLD */ - display_text = g_getenv("DISPLAY"); - LOGM((LOG_LEVEL_INFO, "main: DISPLAY env var set to %s", display_text)); - get_display_num_from_display(display_text); - if (g_display_num == 0) - { - LOGM((LOG_LEVEL_ERROR, "main: error, display is zero")); - g_deinit(); - return 1; - } - LOGM((LOG_LEVEL_INFO, "main: using DISPLAY %d", g_display_num)); - g_snprintf(text, 255, "xrdp_chansrv_%8.8x_main_term", pid); - g_term_event = g_create_wait_obj(text); - g_snprintf(text, 255, "xrdp_chansrv_%8.8x_thread_done", pid); - g_thread_done_event = g_create_wait_obj(text); - g_snprintf(text, 255, "xrdp_chansrv_%8.8x_exec", pid); - g_exec_event = g_create_wait_obj(text); - g_exec_mutex = tc_mutex_create(); - g_exec_sem = tc_sem_create(0); - tc_thread_create(channel_thread_loop, 0); - while (g_term_event > 0 && !g_is_wait_obj_set(g_term_event)) - { - waiters[0] = g_term_event; - waiters[1] = g_exec_event; - if (g_obj_wait(waiters, 2, 0, 0, 0) != 0) - { - LOGM((LOG_LEVEL_ERROR, "main: error, g_obj_wait failed")); - break; - } - if (g_is_wait_obj_set(g_term_event)) - { - break; - } - if (g_is_wait_obj_set(g_exec_event)) - { - g_reset_wait_obj(g_exec_event); - run_exec(); - } - } - while (g_thread_done_event > 0 && !g_is_wait_obj_set(g_thread_done_event)) - { - /* wait for thread to exit */ - if (g_obj_wait(&g_thread_done_event, 1, 0, 0, 0) != 0) - { - LOGM((LOG_LEVEL_ERROR, "main: error, g_obj_wait failed")); - break; - } - } - /* cleanup */ - main_cleanup(); - LOGM((LOG_LEVEL_INFO, "main: app exiting pid %d(0x%8.8x)", pid, pid)); - g_deinit(); - return 0; + return 0; } diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index 3bea9704..1541170d 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -48,10 +48,10 @@ static char g_bmp_image_header[] = extern int g_cliprdr_chan_id; /* in chansrv.c */ -extern Display* g_display; /* in xcommon.c */ +extern Display *g_display; /* in xcommon.c */ extern int g_x_socket; /* in xcommon.c */ extern tbus g_x_wait_obj; /* in xcommon.c */ -extern Screen* g_screen; /* in xcommon.c */ +extern Screen *g_screen; /* in xcommon.c */ extern int g_screen_num; /* in xcommon.c */ int g_clip_up = 0; @@ -73,18 +73,18 @@ static Window g_wnd = 0; static int g_xfixes_event_base = 0; static int g_last_clip_size = 0; -static char* g_last_clip_data = 0; +static char *g_last_clip_data = 0; static Atom g_last_clip_type = 0; static int g_got_selection = 0; /* boolean */ static Time g_selection_time = 0; -static struct stream* g_ins = 0; +static struct stream *g_ins = 0; static XSelectionRequestEvent g_selection_request_event[16]; static int g_selection_request_event_count = 0; -static char* g_data_in = 0; +static char *g_data_in = 0; static int g_data_in_size = 0; static int g_data_in_time = 0; static int g_data_in_up_to_date = 0; @@ -98,7 +98,7 @@ static XSelectionRequestEvent g_saved_selection_req_event; static Atom g_incr_atom; static Atom g_incr_atom_type; static Atom g_incr_atom_target; -static char* g_incr_data = 0; +static char *g_incr_data = 0; static int g_incr_data_size = 0; static int g_incr_in_progress = 0; @@ -109,19 +109,22 @@ static int clipboard_format_id = CB_FORMAT_UNICODETEXT; static Time APP_CC clipboard_get_server_time(void) { - XEvent xevent; - unsigned char no_text[4]; + XEvent xevent; + unsigned char no_text[4]; - /* append nothing */ - no_text[0] = 0; - XChangeProperty(g_display, g_wnd, g_get_time_atom, XA_STRING, 8, - PropModeAppend, no_text, 0); - /* wait for PropertyNotify */ - do - { - XMaskEvent(g_display, PropertyChangeMask, &xevent); - } while (xevent.type != PropertyNotify); - return xevent.xproperty.time; + /* append nothing */ + no_text[0] = 0; + XChangeProperty(g_display, g_wnd, g_get_time_atom, XA_STRING, 8, + PropModeAppend, no_text, 0); + + /* wait for PropertyNotify */ + do + { + XMaskEvent(g_display, PropertyChangeMask, &xevent); + } + while (xevent.type != PropertyNotify); + + return xevent.xproperty.time; } /*****************************************************************************/ @@ -132,7 +135,7 @@ clipboard_get_server_time(void) static int APP_CC clipboard_get_local_time(void) { - return g_time3(); + return g_time3(); } /*****************************************************************************/ @@ -140,386 +143,416 @@ clipboard_get_local_time(void) int APP_CC clipboard_init(void) { - struct stream* s; - int size; - int rv; - int input_mask; - int dummy; - int ver_maj; - int ver_min; - Status st; + struct stream *s; + int size; + int rv; + int input_mask; + int dummy; + int ver_maj; + int ver_min; + Status st; - LOGM((LOG_LEVEL_DEBUG, "xrdp-chansrv: in clipboard_init")); - if (g_clip_up) - { - return 0; - } - xcommon_init(); - clipboard_deinit(); - rv = 0; - if (rv == 0) - { - g_clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False); - if (g_clipboard_atom == None) - { - LOGM((LOG_LEVEL_ERROR, "clipboard_init: XInternAtom failed")); - rv = 3; - } - } - if (rv == 0) - { - if (!XFixesQueryExtension(g_display, &g_xfixes_event_base, &dummy)) - { - LOGM((LOG_LEVEL_ERROR, "clipboard_init: no xfixes")); - rv = 5; - } - } - if (rv == 0) - { - LOGM((LOG_LEVEL_DEBUG, "clipboard_init: g_xfixes_event_base %d", - g_xfixes_event_base)); - st = XFixesQueryVersion(g_display, &ver_maj, &ver_min); - LOGM((LOG_LEVEL_DEBUG, "clipboard_init st %d, maj %d min %d", st, - ver_maj, ver_min)); - g_clip_property_atom = XInternAtom(g_display, "XRDP_CLIP_PROPERTY_ATOM", - False); - g_get_time_atom = XInternAtom(g_display, "XRDP_GET_TIME_ATOM", - False); - g_timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False); - g_targets_atom = XInternAtom(g_display, "TARGETS", False); - g_multiple_atom = XInternAtom(g_display, "MULTIPLE", False); - g_primary_atom = XInternAtom(g_display, "PRIMARY", False); - g_secondary_atom = XInternAtom(g_display, "SECONDARY", False); - g_utf8_atom = XInternAtom(g_display, "UTF8_STRING", False); + LOGM((LOG_LEVEL_DEBUG, "xrdp-chansrv: in clipboard_init")); - g_image_bmp_atom = XInternAtom(g_display, "image/bmp", False); - g_incr_atom = XInternAtom(g_display, "INCR", False); - if (g_image_bmp_atom == None) + if (g_clip_up) { - LOGM((LOG_LEVEL_ERROR, "clipboard_init: g_image_bmp_atom was " - "not allocated")); + return 0; } - g_wnd = XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), - 0, 0, 4, 4, 0, 0, 0); - input_mask = StructureNotifyMask | PropertyChangeMask; - XSelectInput(g_display, g_wnd, input_mask); - //XMapWindow(g_display, g_wnd); - XFixesSelectSelectionInput(g_display, g_wnd, - g_clipboard_atom, - XFixesSetSelectionOwnerNotifyMask | - XFixesSelectionWindowDestroyNotifyMask | - XFixesSelectionClientCloseNotifyMask); - } - if (rv == 0) - { - make_stream(s); - init_stream(s, 8192); - out_uint16_le(s, 1); /* CLIPRDR_CONNECT */ - out_uint16_le(s, 0); /* status */ - out_uint32_le(s, 0); /* length */ - out_uint32_le(s, 0); /* extra 4 bytes ? */ - s_mark_end(s); - size = (int)(s->end - s->data); - LOGM((LOG_LEVEL_DEBUG, "clipboard_init: data out, sending " - "CLIPRDR_CONNECT (clip_msg_id = 1)")); - rv = send_channel_data(g_cliprdr_chan_id, s->data, size); - if (rv != 0) + xcommon_init(); + clipboard_deinit(); + rv = 0; + + if (rv == 0) { - LOGM((LOG_LEVEL_ERROR, "clipboard_init: send_channel_data failed " - "rv = %d", rv)); - rv = 4; + g_clipboard_atom = XInternAtom(g_display, "CLIPBOARD", False); + + if (g_clipboard_atom == None) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_init: XInternAtom failed")); + rv = 3; + } } - free_stream(s); - } - if (rv == 0) - { - g_clip_up = 1; - make_stream(g_ins); - init_stream(g_ins, 8192); - } - else - { - LOGM((LOG_LEVEL_ERROR, "xrdp-chansrv: clipboard_init: error on exit")); - } - return rv; + + if (rv == 0) + { + if (!XFixesQueryExtension(g_display, &g_xfixes_event_base, &dummy)) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_init: no xfixes")); + rv = 5; + } + } + + if (rv == 0) + { + LOGM((LOG_LEVEL_DEBUG, "clipboard_init: g_xfixes_event_base %d", + g_xfixes_event_base)); + st = XFixesQueryVersion(g_display, &ver_maj, &ver_min); + LOGM((LOG_LEVEL_DEBUG, "clipboard_init st %d, maj %d min %d", st, + ver_maj, ver_min)); + g_clip_property_atom = XInternAtom(g_display, "XRDP_CLIP_PROPERTY_ATOM", + False); + g_get_time_atom = XInternAtom(g_display, "XRDP_GET_TIME_ATOM", + False); + g_timestamp_atom = XInternAtom(g_display, "TIMESTAMP", False); + g_targets_atom = XInternAtom(g_display, "TARGETS", False); + g_multiple_atom = XInternAtom(g_display, "MULTIPLE", False); + g_primary_atom = XInternAtom(g_display, "PRIMARY", False); + g_secondary_atom = XInternAtom(g_display, "SECONDARY", False); + g_utf8_atom = XInternAtom(g_display, "UTF8_STRING", False); + + g_image_bmp_atom = XInternAtom(g_display, "image/bmp", False); + g_incr_atom = XInternAtom(g_display, "INCR", False); + + if (g_image_bmp_atom == None) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_init: g_image_bmp_atom was " + "not allocated")); + } + + g_wnd = XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), + 0, 0, 4, 4, 0, 0, 0); + input_mask = StructureNotifyMask | PropertyChangeMask; + XSelectInput(g_display, g_wnd, input_mask); + //XMapWindow(g_display, g_wnd); + XFixesSelectSelectionInput(g_display, g_wnd, + g_clipboard_atom, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + } + + if (rv == 0) + { + make_stream(s); + init_stream(s, 8192); + out_uint16_le(s, 1); /* CLIPRDR_CONNECT */ + out_uint16_le(s, 0); /* status */ + out_uint32_le(s, 0); /* length */ + out_uint32_le(s, 0); /* extra 4 bytes ? */ + s_mark_end(s); + size = (int)(s->end - s->data); + LOGM((LOG_LEVEL_DEBUG, "clipboard_init: data out, sending " + "CLIPRDR_CONNECT (clip_msg_id = 1)")); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + + if (rv != 0) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_init: send_channel_data failed " + "rv = %d", rv)); + rv = 4; + } + + free_stream(s); + } + + if (rv == 0) + { + g_clip_up = 1; + make_stream(g_ins); + init_stream(g_ins, 8192); + } + else + { + LOGM((LOG_LEVEL_ERROR, "xrdp-chansrv: clipboard_init: error on exit")); + } + + return rv; } /*****************************************************************************/ int APP_CC clipboard_deinit(void) { - if (g_wnd != 0) - { - XDestroyWindow(g_display, g_wnd); - g_wnd = 0; - } - g_free(g_last_clip_data); - g_last_clip_data = 0; - g_last_clip_size = 0; - free_stream(g_ins); - g_ins = 0; - g_clip_up = 0; - return 0; + if (g_wnd != 0) + { + XDestroyWindow(g_display, g_wnd); + g_wnd = 0; + } + + g_free(g_last_clip_data); + g_last_clip_data = 0; + g_last_clip_size = 0; + free_stream(g_ins); + g_ins = 0; + g_clip_up = 0; + return 0; } /*****************************************************************************/ static int APP_CC clipboard_send_data_request(void) { - struct stream* s; - int size; - int rv; + struct stream *s; + int size; + int rv; - LOGM((LOG_LEVEL_DEBUG, "clipboard_send_data_request:")); - if (!g_got_format_announce) - { - LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_request: error, " - "no format announce")); - return 0; - } - g_got_format_announce = 0; - make_stream(s); - init_stream(s, 8192); - out_uint16_le(s, 4); /* CLIPRDR_DATA_REQUEST */ - out_uint16_le(s, 0); /* status */ - out_uint32_le(s, 4); /* length */ - out_uint32_le(s, clipboard_format_id); - s_mark_end(s); - size = (int)(s->end - s->data); - LOGM((LOG_LEVEL_DEBUG,"clipboard_send_data_request: data out, sending " - "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)")); - rv = send_channel_data(g_cliprdr_chan_id, s->data, size); - free_stream(s); - return rv; + LOGM((LOG_LEVEL_DEBUG, "clipboard_send_data_request:")); + + if (!g_got_format_announce) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_request: error, " + "no format announce")); + return 0; + } + + g_got_format_announce = 0; + make_stream(s); + init_stream(s, 8192); + out_uint16_le(s, 4); /* CLIPRDR_DATA_REQUEST */ + out_uint16_le(s, 0); /* status */ + out_uint32_le(s, 4); /* length */ + out_uint32_le(s, clipboard_format_id); + s_mark_end(s); + size = (int)(s->end - s->data); + LOGM((LOG_LEVEL_DEBUG, "clipboard_send_data_request: data out, sending " + "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)")); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + return rv; } /*****************************************************************************/ static int APP_CC clipboard_send_format_ack(void) { - struct stream* s; - int size; - int rv; + struct stream *s; + int size; + int rv; - make_stream(s); - init_stream(s, 8192); - out_uint16_le(s, 3); /* CLIPRDR_FORMAT_ACK */ - out_uint16_le(s, 1); /* status */ - out_uint32_le(s, 0); /* length */ - out_uint32_le(s, 0); /* extra 4 bytes ? */ - s_mark_end(s); - size = (int)(s->end - s->data); - LOGM((LOG_LEVEL_DEBUG,"clipboard_send_format_ack: data out, sending " - "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)")); - rv = send_channel_data(g_cliprdr_chan_id, s->data, size); - free_stream(s); - return rv; + make_stream(s); + init_stream(s, 8192); + out_uint16_le(s, 3); /* CLIPRDR_FORMAT_ACK */ + out_uint16_le(s, 1); /* status */ + out_uint32_le(s, 0); /* length */ + out_uint32_le(s, 0); /* extra 4 bytes ? */ + s_mark_end(s); + size = (int)(s->end - s->data); + LOGM((LOG_LEVEL_DEBUG, "clipboard_send_format_ack: data out, sending " + "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)")); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + return rv; } static char windows_native_format[] = { - 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 int APP_CC -clipboard_send_format_announce(tui32 format_id, char* format_name) +clipboard_send_format_announce(tui32 format_id, char *format_name) { - struct stream* s; - int size; - int rv; + struct stream *s; + int size; + int rv; - make_stream(s); - init_stream(s, 8192); - out_uint16_le(s, 2); /* CLIPRDR_FORMAT_ANNOUNCE */ - out_uint16_le(s, 0); /* status */ - out_uint32_le(s, 4 + sizeof(windows_native_format)); /* length */ - out_uint32_le(s, format_id); - out_uint8p(s, windows_native_format, sizeof(windows_native_format)); - s_mark_end(s); - size = (int)(s->end - s->data); - LOGM((LOG_LEVEL_DEBUG,"clipboard_send_format_announce: data out, sending " - "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)")); - rv = send_channel_data(g_cliprdr_chan_id, s->data, size); - free_stream(s); - return rv; + make_stream(s); + init_stream(s, 8192); + out_uint16_le(s, 2); /* CLIPRDR_FORMAT_ANNOUNCE */ + out_uint16_le(s, 0); /* status */ + out_uint32_le(s, 4 + sizeof(windows_native_format)); /* length */ + out_uint32_le(s, format_id); + out_uint8p(s, windows_native_format, sizeof(windows_native_format)); + s_mark_end(s); + size = (int)(s->end - s->data); + LOGM((LOG_LEVEL_DEBUG, "clipboard_send_format_announce: data out, sending " + "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)")); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + return rv; } /*****************************************************************************/ /* returns number of bytes written */ static int APP_CC -clipboard_out_unicode(struct stream* s, char* text, int num_chars) +clipboard_out_unicode(struct stream *s, char *text, int num_chars) { - int index; - int lnum_chars; - twchar* ltext; + int index; + int lnum_chars; + twchar *ltext; - if ((num_chars < 1) || (text == 0)) - { - return 0; - } - lnum_chars = g_mbstowcs(0, text, num_chars); - if (lnum_chars < 0) - { - return 0; - } - ltext = g_malloc((num_chars + 1) * sizeof(twchar), 1); - g_mbstowcs(ltext, text, num_chars); - index = 0; - while (index < num_chars) - { - out_uint16_le(s, ltext[index]); - index++; - } - g_free(ltext); - return index * 2; + if ((num_chars < 1) || (text == 0)) + { + return 0; + } + + lnum_chars = g_mbstowcs(0, text, num_chars); + + if (lnum_chars < 0) + { + return 0; + } + + ltext = g_malloc((num_chars + 1) * sizeof(twchar), 1); + g_mbstowcs(ltext, text, num_chars); + index = 0; + + while (index < num_chars) + { + out_uint16_le(s, ltext[index]); + index++; + } + + g_free(ltext); + return index * 2; } /*****************************************************************************/ static int APP_CC clipboard_send_data_response_for_image(void) { - struct stream* s; - int size; - int rv; + struct stream *s; + int size; + int rv; - LOG(10, ("clipboard_send_data_response_for_image: g_last_clip_size %d\n", - g_last_clip_size)); - make_stream(s); - init_stream(s, 64 + g_last_clip_size); - out_uint16_le(s, 5); /* CLIPRDR_DATA_RESPONSE */ - out_uint16_le(s, 1); /* status */ - out_uint32_le(s, g_last_clip_size); /* length */ - /* insert image data */ - if (g_last_clip_type == g_image_bmp_atom) - { - /* do not insert first header */ - out_uint8p(s, g_last_clip_data + 14, g_last_clip_size - 14); - } - out_uint16_le(s, 0); /* nil for string */ - out_uint32_le(s, 0); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - s_mark_end(s); - size = (int)(s->end - s->data); - /* HANGING HERE WHEN IMAGE DATA IS TOO BIG!!!! */ - rv = send_channel_data(g_cliprdr_chan_id, s->data, size); - free_stream(s); - return rv; + LOG(10, ("clipboard_send_data_response_for_image: g_last_clip_size %d\n", + g_last_clip_size)); + make_stream(s); + init_stream(s, 64 + g_last_clip_size); + out_uint16_le(s, 5); /* CLIPRDR_DATA_RESPONSE */ + out_uint16_le(s, 1); /* status */ + out_uint32_le(s, g_last_clip_size); /* length */ + + /* insert image data */ + if (g_last_clip_type == g_image_bmp_atom) + { + /* do not insert first header */ + out_uint8p(s, g_last_clip_data + 14, g_last_clip_size - 14); + } + + out_uint16_le(s, 0); /* nil for string */ + out_uint32_le(s, 0); + out_uint32_le(s, 0); + out_uint32_le(s, 0); + s_mark_end(s); + size = (int)(s->end - s->data); + /* HANGING HERE WHEN IMAGE DATA IS TOO BIG!!!! */ + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + return rv; } /*****************************************************************************/ static int APP_CC clipboard_send_data_response(void) { - struct stream* s; - int size; - int rv; - int num_chars; + struct stream *s; + int size; + int rv; + int num_chars; - LOG(10, ("clipboard_send_data_response:")); - num_chars = 0; - if (g_last_clip_data != 0) - { - if (g_last_clip_type == g_image_bmp_atom) + LOG(10, ("clipboard_send_data_response:")); + num_chars = 0; + + if (g_last_clip_data != 0) { - return clipboard_send_data_response_for_image(); + if (g_last_clip_type == g_image_bmp_atom) + { + return clipboard_send_data_response_for_image(); + } + + if ((g_last_clip_type == XA_STRING) || (g_last_clip_type == g_utf8_atom)) + { + num_chars = g_mbstowcs(0, g_last_clip_data, 0); + + if (num_chars < 0) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_response: bad string")); + num_chars = 0; + } + } } - if ((g_last_clip_type == XA_STRING) || (g_last_clip_type == g_utf8_atom)) + + LOG(10, ("clipboard_send_data_response: g_last_clip_size %d " + "num_chars %d", g_last_clip_size, num_chars)); + make_stream(s); + init_stream(s, 64 + num_chars * 2); + out_uint16_le(s, 5); /* CLIPRDR_DATA_RESPONSE */ + out_uint16_le(s, 1); /* status */ + out_uint32_le(s, num_chars * 2 + 2); /* length */ + + if (clipboard_out_unicode(s, g_last_clip_data, num_chars) != num_chars * 2) { - num_chars = g_mbstowcs(0, g_last_clip_data, 0); - if (num_chars < 0) - { - LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_response: bad string")); - num_chars = 0; - } + LOGM((LOG_LEVEL_ERROR, "clipboard_send_data_response: error " + "clipboard_out_unicode didn't write right number of bytes")); } - } - LOG(10, ("clipboard_send_data_response: g_last_clip_size %d " - "num_chars %d", g_last_clip_size, num_chars)); - make_stream(s); - init_stream(s, 64 + num_chars * 2); - out_uint16_le(s, 5); /* CLIPRDR_DATA_RESPONSE */ - out_uint16_le(s, 1); /* status */ - out_uint32_le(s, num_chars * 2 + 2); /* length */ - if (clipboard_out_unicode(s, g_last_clip_data, num_chars) != num_chars * 2) - { - LOGM((LOG_LEVEL_ERROR,"clipboard_send_data_response: error " - "clipboard_out_unicode didn't write right number of bytes")); - } - out_uint16_le(s, 0); /* nil for string */ - out_uint32_le(s, 0); - s_mark_end(s); - size = (int)(s->end - s->data); - LOGM((LOG_LEVEL_DEBUG,"clipboard_send_data_response: data out, sending " - "CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d num_chars %d", - size, num_chars)); - rv = send_channel_data(g_cliprdr_chan_id, s->data, size); - free_stream(s); - return rv; + + out_uint16_le(s, 0); /* nil for string */ + out_uint32_le(s, 0); + s_mark_end(s); + size = (int)(s->end - s->data); + LOGM((LOG_LEVEL_DEBUG, "clipboard_send_data_response: data out, sending " + "CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d num_chars %d", + size, num_chars)); + rv = send_channel_data(g_cliprdr_chan_id, s->data, size); + free_stream(s); + return rv; } /*****************************************************************************/ static int APP_CC clipboard_set_selection_owner(void) { - Window owner; + Window owner; - g_selection_time = clipboard_get_server_time(); - XSetSelectionOwner(g_display, g_clipboard_atom, g_wnd, g_selection_time); - owner = XGetSelectionOwner(g_display, g_clipboard_atom); - if (owner != g_wnd) - { - g_got_selection = 0; - return 1; - } - g_got_selection = 1; - return 0; + g_selection_time = clipboard_get_server_time(); + XSetSelectionOwner(g_display, g_clipboard_atom, g_wnd, g_selection_time); + owner = XGetSelectionOwner(g_display, g_clipboard_atom); + + if (owner != g_wnd) + { + g_got_selection = 0; + return 1; + } + + g_got_selection = 1; + return 0; } /*****************************************************************************/ static int APP_CC -clipboard_provide_selection(XSelectionRequestEvent* req, Atom type, int format, - char* data, int length) +clipboard_provide_selection(XSelectionRequestEvent *req, Atom type, int format, + char *data, int length) { - XEvent xev; + XEvent xev; - XChangeProperty(g_display, req->requestor, req->property, - type, format, PropModeReplace, (tui8*)data, length); - g_memset(&xev, 0, sizeof(xev)); - xev.xselection.type = SelectionNotify; - xev.xselection.send_event = True; - xev.xselection.display = req->display; - 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); - return 0; + XChangeProperty(g_display, req->requestor, req->property, + type, format, PropModeReplace, (tui8 *)data, length); + g_memset(&xev, 0, sizeof(xev)); + xev.xselection.type = SelectionNotify; + xev.xselection.send_event = True; + xev.xselection.display = req->display; + 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); + return 0; } /*****************************************************************************/ static int APP_CC -clipboard_refuse_selection(XSelectionRequestEvent* req) +clipboard_refuse_selection(XSelectionRequestEvent *req) { - XEvent xev; + XEvent xev; - g_memset(&xev, 0, sizeof(xev)); - xev.xselection.type = SelectionNotify; - xev.xselection.send_event = True; - xev.xselection.display = req->display; - 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); - return 0; + g_memset(&xev, 0, sizeof(xev)); + xev.xselection.type = SelectionNotify; + xev.xselection.send_event = True; + xev.xselection.display = req->display; + 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); + return 0; } /*****************************************************************************/ @@ -527,47 +560,49 @@ clipboard_refuse_selection(XSelectionRequestEvent* req) updated with new clipboard data; contains Clipboard Format ID and name pairs of new Clipboard Formats on the clipboard. */ static int APP_CC -clipboard_process_format_announce(struct stream* s, int clip_msg_status, +clipboard_process_format_announce(struct stream *s, int clip_msg_status, int clip_msg_len) { - LOGM((LOG_LEVEL_DEBUG, "clipboard_process_format_announce: " - "CLIPRDR_FORMAT_ANNOUNCE")); - //g_hexdump(s->p, s->end - s->p); - clipboard_send_format_ack(); - g_got_format_announce = 1; - g_data_in_up_to_date = 0; - if (clipboard_set_selection_owner() != 0) - { - LOGM((LOG_LEVEL_ERROR, "clipboard_process_format_announce: " - "XSetSelectionOwner failed")); - } - return 0; + LOGM((LOG_LEVEL_DEBUG, "clipboard_process_format_announce: " + "CLIPRDR_FORMAT_ANNOUNCE")); + //g_hexdump(s->p, s->end - s->p); + clipboard_send_format_ack(); + g_got_format_announce = 1; + g_data_in_up_to_date = 0; + + if (clipboard_set_selection_owner() != 0) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_process_format_announce: " + "XSetSelectionOwner failed")); + } + + return 0; } /*****************************************************************************/ /* response to CB_FORMAT_LIST; used to indicate whether processing of the Format List PDU was successful */ static int APP_CC -clipboard_prcoess_format_ack(struct stream* s, int clip_msg_status, +clipboard_prcoess_format_ack(struct stream *s, int clip_msg_status, int clip_msg_len) { - LOGM((LOG_LEVEL_DEBUG,"clipboard_prcoess_format_ack: CLIPRDR_FORMAT_ACK")); - //g_hexdump(s->p, s->end - s->p); - return 0; + LOGM((LOG_LEVEL_DEBUG, "clipboard_prcoess_format_ack: CLIPRDR_FORMAT_ACK")); + //g_hexdump(s->p, s->end - s->p); + return 0; } /*****************************************************************************/ /* sent by recipient of CB_FORMAT_LIST; used to request data for one of the formats that was listed in CB_FORMAT_LIST */ static int APP_CC -clipboard_process_data_request(struct stream* s, int clip_msg_status, +clipboard_process_data_request(struct stream *s, int clip_msg_status, int clip_msg_len) { - LOGM((LOG_LEVEL_DEBUG,"clipboard_process_data_request: " - "CLIPRDR_DATA_REQUEST")); - //g_hexdump(s->p, s->end - s->p); - clipboard_send_data_response(); - return 0; + LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_request: " + "CLIPRDR_DATA_REQUEST")); + //g_hexdump(s->p, s->end - s->p); + clipboard_send_data_response(); + return 0; } /*****************************************************************************/ @@ -576,54 +611,61 @@ clipboard_process_data_request(struct stream* s, int clip_msg_status, was successful, CB_FORMAT_DATA_RESPONSE includes contents of requested clipboard data. */ static int APP_CC -clipboard_process_data_response_for_image(struct stream * s, - int clip_msg_status, - int clip_msg_len) +clipboard_process_data_response_for_image(struct stream *s, + int clip_msg_status, + int clip_msg_len) { - XSelectionRequestEvent* lxev = &g_saved_selection_req_event; - char* cptr; - char cdata; - int len; - int index; + XSelectionRequestEvent *lxev = &g_saved_selection_req_event; + char *cptr; + char cdata; + int len; + int index; - LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: " - "CLIPRDR_DATA_RESPONSE_FOR_IMAGE")); - g_waiting_for_data_response = 0; - len = (int)(s->end - s->p); - if (len < 1) - { - return 0; - } - if (g_last_clip_type == g_image_bmp_atom) - { - /* space for inserting bmp image header */ - len += 14; - cptr = (char*)g_malloc(len, 0); - if (cptr == 0) + LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: " + "CLIPRDR_DATA_RESPONSE_FOR_IMAGE")); + g_waiting_for_data_response = 0; + len = (int)(s->end - s->p); + + if (len < 1) { - return 0; + return 0; } - g_memcpy(cptr, g_bmp_image_header, 14); - index = 14; - } - else - { + + if (g_last_clip_type == g_image_bmp_atom) + { + /* space for inserting bmp image header */ + len += 14; + cptr = (char *)g_malloc(len, 0); + + if (cptr == 0) + { + return 0; + } + + g_memcpy(cptr, g_bmp_image_header, 14); + index = 14; + } + else + { + return 0; + } + + while (s_check(s)) + { + in_uint8(s, cdata); + cptr[index++] = cdata; + } + + if (len >= 0) + { + g_data_in = cptr; + g_data_in_size = len; + g_data_in_time = clipboard_get_local_time(); + g_data_in_up_to_date = 1; + } + + clipboard_provide_selection(lxev, lxev->target, 8, cptr, len); return 0; - } - while (s_check(s)) - { - in_uint8(s, cdata); - cptr[index++] = cdata; - } - if (len >= 0) - { - g_data_in = cptr; - g_data_in_size = len; - g_data_in_time = clipboard_get_local_time(); - g_data_in_up_to_date = 1; - } - clipboard_provide_selection(lxev, lxev->target, 8, cptr, len); - return 0; } /*****************************************************************************/ @@ -633,159 +675,181 @@ clipboard_process_data_response_for_image(struct stream * s, clipboard data. */ /*****************************************************************************/ static int APP_CC -clipboard_process_data_response(struct stream* s, int clip_msg_status, +clipboard_process_data_response(struct stream *s, int clip_msg_status, int clip_msg_len) { - XSelectionRequestEvent* lxev; - twchar* wtext; - twchar wchr; - int len; - int index; - int data_in_len; + XSelectionRequestEvent *lxev; + twchar *wtext; + twchar wchr; + int len; + int index; + int data_in_len; - if (g_want_image_data) - { - g_want_image_data = 0; - clipboard_process_data_response_for_image(s, clip_msg_status, clip_msg_len); - return 0; - } - LOGM((LOG_LEVEL_DEBUG,"clipboard_process_data_response: " - "CLIPRDR_DATA_RESPONSE")); - g_waiting_for_data_response = 0; - len = (int)(s->end - s->p); - if (len < 1) - { - return 0; - } - //g_hexdump(s->p, len); - wtext = (twchar*)g_malloc(((len / 2) + 1) * sizeof(twchar), 0); - if (wtext == 0) - { - return 0; - } - index = 0; - while (s_check(s)) - { - in_uint16_le(s, wchr); - wtext[index] = wchr; - if (wchr == 0) + if (g_want_image_data) { - break; + g_want_image_data = 0; + clipboard_process_data_response_for_image(s, clip_msg_status, clip_msg_len); + return 0; } - index++; - } - wtext[index] = 0; - g_free(g_data_in); - g_data_in = 0; - g_data_in_size = 0; - g_data_in_time = 0; - len = g_wcstombs(0, wtext, 0); - if (len >= 0) - { - g_data_in = (char*)g_malloc(len + 16, 0); - if (g_data_in == 0) + + LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_response: " + "CLIPRDR_DATA_RESPONSE")); + g_waiting_for_data_response = 0; + len = (int)(s->end - s->p); + + if (len < 1) { - g_free(wtext); - return 0; + return 0; } - g_data_in_size = len; - g_wcstombs(g_data_in, wtext, len + 1); - g_data_in_time = xcommon_get_local_time(); - g_data_in_up_to_date = 1; - } - if (g_data_in != 0) - { - data_in_len = g_strlen(g_data_in); - for (index = 0; index < g_selection_request_event_count; index++) + + //g_hexdump(s->p, len); + wtext = (twchar *)g_malloc(((len / 2) + 1) * sizeof(twchar), 0); + + if (wtext == 0) { - lxev = &(g_selection_request_event[index]); - clipboard_provide_selection(lxev, lxev->target, 8, g_data_in, - data_in_len); - LOGM((LOG_LEVEL_DEBUG,"clipboard_process_data_response: requestor %d " - "data_in_len %d", lxev->requestor, data_in_len)); + return 0; } - } - g_selection_request_event_count = 0; - g_free(wtext); - return 0; + + index = 0; + + while (s_check(s)) + { + in_uint16_le(s, wchr); + wtext[index] = wchr; + + if (wchr == 0) + { + break; + } + + index++; + } + + wtext[index] = 0; + g_free(g_data_in); + g_data_in = 0; + g_data_in_size = 0; + g_data_in_time = 0; + len = g_wcstombs(0, wtext, 0); + + if (len >= 0) + { + g_data_in = (char *)g_malloc(len + 16, 0); + + if (g_data_in == 0) + { + g_free(wtext); + return 0; + } + + g_data_in_size = len; + g_wcstombs(g_data_in, wtext, len + 1); + g_data_in_time = xcommon_get_local_time(); + g_data_in_up_to_date = 1; + } + + if (g_data_in != 0) + { + data_in_len = g_strlen(g_data_in); + + for (index = 0; index < g_selection_request_event_count; index++) + { + lxev = &(g_selection_request_event[index]); + clipboard_provide_selection(lxev, lxev->target, 8, g_data_in, + data_in_len); + LOGM((LOG_LEVEL_DEBUG, "clipboard_process_data_response: requestor %d " + "data_in_len %d", lxev->requestor, data_in_len)); + } + } + + g_selection_request_event_count = 0; + g_free(wtext); + return 0; } /*****************************************************************************/ int APP_CC -clipboard_data_in(struct stream* s, int chan_id, int chan_flags, int length, +clipboard_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) { - int clip_msg_id; - int clip_msg_len; - int clip_msg_status; - int rv; - struct stream* ls; + int clip_msg_id; + int clip_msg_len; + int clip_msg_status; + int rv; + struct stream *ls; - LOG(10, ("clipboard_data_in: chan_is %d " - "chan_flags %d length %d total_length %d", - chan_id, chan_flags, length, total_length)); - if ((chan_flags & 3) == 3) - { - ls = s; - } - else - { - if (chan_flags & 1) + LOG(10, ("clipboard_data_in: chan_is %d " + "chan_flags %d length %d total_length %d", + chan_id, chan_flags, length, total_length)); + + if ((chan_flags & 3) == 3) { - init_stream(g_ins, total_length); + ls = s; } - in_uint8a(s, g_ins->end, length); - g_ins->end += length; - if ((chan_flags & 2) == 0) + else { - return 0; + if (chan_flags & 1) + { + init_stream(g_ins, total_length); + } + + in_uint8a(s, g_ins->end, length); + g_ins->end += length; + + if ((chan_flags & 2) == 0) + { + return 0; + } + + ls = g_ins; } - ls = g_ins; - } - in_uint16_le(ls, clip_msg_id); - in_uint16_le(ls, clip_msg_status); - in_uint32_le(ls, clip_msg_len); - LOG(10, ("clipboard_data_in: clip_msg_id %d " - "clip_msg_status %d clip_msg_len %d", - clip_msg_id, clip_msg_status, clip_msg_len)); - rv = 0; - switch (clip_msg_id) - { - /* sent by client or server when its local system clipboard is */ - /* updated with new clipboard data; contains Clipboard Format ID */ - /* and name pairs of new Clipboard Formats on the clipboard. */ - case CB_FORMAT_LIST: /* CLIPRDR_FORMAT_ANNOUNCE */ - rv = clipboard_process_format_announce(ls, clip_msg_status, - clip_msg_len); - break; - /* response to CB_FORMAT_LIST; used to indicate whether */ - /* processing of the Format List PDU was successful */ - case CB_FORMAT_LIST_RESPONSE: /* CLIPRDR_FORMAT_ACK */ - rv = clipboard_prcoess_format_ack(ls, clip_msg_status, - clip_msg_len); - break; - /* sent by recipient of CB_FORMAT_LIST; used to request data for one */ - /* of the formats that was listed in CB_FORMAT_LIST */ - case CB_FORMAT_DATA_REQUEST: /* CLIPRDR_DATA_REQUEST */ - rv = clipboard_process_data_request(ls, clip_msg_status, - clip_msg_len); - break; - /* sent as a reply to CB_FORMAT_DATA_REQUEST; used to indicate */ - /* whether processing of the CB_FORMAT_DATA_REQUEST was */ - /* successful; if processing was successful, */ - /* CB_FORMAT_DATA_RESPONSE includes contents of requested */ - /* clipboard data. */ - case CB_FORMAT_DATA_RESPONSE: /* CLIPRDR_DATA_RESPONSE */ - rv = clipboard_process_data_response(ls, clip_msg_status, - clip_msg_len); - break; - default: - LOGM((LOG_LEVEL_ERROR, "clipboard_data_in: unknown clip_msg_id %d", - clip_msg_id)); - break; - } - XFlush(g_display); - return rv; + + in_uint16_le(ls, clip_msg_id); + in_uint16_le(ls, clip_msg_status); + in_uint32_le(ls, clip_msg_len); + LOG(10, ("clipboard_data_in: clip_msg_id %d " + "clip_msg_status %d clip_msg_len %d", + clip_msg_id, clip_msg_status, clip_msg_len)); + rv = 0; + + switch (clip_msg_id) + { + /* sent by client or server when its local system clipboard is */ + /* updated with new clipboard data; contains Clipboard Format ID */ + /* and name pairs of new Clipboard Formats on the clipboard. */ + case CB_FORMAT_LIST: /* CLIPRDR_FORMAT_ANNOUNCE */ + rv = clipboard_process_format_announce(ls, clip_msg_status, + clip_msg_len); + break; + /* response to CB_FORMAT_LIST; used to indicate whether */ + /* processing of the Format List PDU was successful */ + case CB_FORMAT_LIST_RESPONSE: /* CLIPRDR_FORMAT_ACK */ + rv = clipboard_prcoess_format_ack(ls, clip_msg_status, + clip_msg_len); + break; + /* sent by recipient of CB_FORMAT_LIST; used to request data for one */ + /* of the formats that was listed in CB_FORMAT_LIST */ + case CB_FORMAT_DATA_REQUEST: /* CLIPRDR_DATA_REQUEST */ + rv = clipboard_process_data_request(ls, clip_msg_status, + clip_msg_len); + break; + /* sent as a reply to CB_FORMAT_DATA_REQUEST; used to indicate */ + /* whether processing of the CB_FORMAT_DATA_REQUEST was */ + /* successful; if processing was successful, */ + /* CB_FORMAT_DATA_RESPONSE includes contents of requested */ + /* clipboard data. */ + case CB_FORMAT_DATA_RESPONSE: /* CLIPRDR_DATA_RESPONSE */ + rv = clipboard_process_data_response(ls, clip_msg_status, + clip_msg_len); + break; + default: + LOGM((LOG_LEVEL_ERROR, "clipboard_data_in: unknown clip_msg_id %d", + clip_msg_id)); + break; + } + + XFlush(g_display); + return rv; } /*****************************************************************************/ @@ -805,132 +869,151 @@ clipboard_data_in(struct stream* s, int chan_id, int chan_flags, int length, Time selection_timestamp; } XFixesSelectionNotifyEvent; */ static int APP_CC -clipboard_event_selection_owner_notify(XEvent* xevent) +clipboard_event_selection_owner_notify(XEvent *xevent) { - XFixesSelectionNotifyEvent* lxevent; + XFixesSelectionNotifyEvent *lxevent; - lxevent = (XFixesSelectionNotifyEvent*)xevent; - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_owner_notify: " - "window %d subtype %d owner %d g_wnd %d", - lxevent->window, lxevent->subtype, lxevent->owner, g_wnd)); - if (lxevent->owner == g_wnd) - { - LOGM((LOG_LEVEL_DEBUG,"clipboard_event_selection_owner_notify: skipping, " - "onwer == g_wnd")); - g_got_selection = 1; + lxevent = (XFixesSelectionNotifyEvent *)xevent; + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_owner_notify: " + "window %d subtype %d owner %d g_wnd %d", + lxevent->window, lxevent->subtype, lxevent->owner, g_wnd)); + + if (lxevent->owner == g_wnd) + { + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_owner_notify: skipping, " + "onwer == g_wnd")); + g_got_selection = 1; + return 0; + } + + g_got_selection = 0; + XConvertSelection(g_display, g_clipboard_atom, g_targets_atom, + g_clip_property_atom, g_wnd, lxevent->timestamp); return 0; - } - g_got_selection = 0; - XConvertSelection(g_display, g_clipboard_atom, g_targets_atom, - g_clip_property_atom, g_wnd, lxevent->timestamp); - return 0; } /*****************************************************************************/ /* returns error get a window property from wnd */ static int APP_CC -clipboard_get_window_property(Window wnd, Atom prop, Atom* type, int* fmt, - int* n_items, char** xdata, int* xdata_size) +clipboard_get_window_property(Window wnd, Atom prop, Atom *type, int *fmt, + int *n_items, char **xdata, int *xdata_size) { - int lfmt; - int lxdata_size; - unsigned long ln_items; - unsigned long llen_after; - tui8* lxdata; - Atom ltype; + int lfmt; + int lxdata_size; + unsigned long ln_items; + unsigned long llen_after; + tui8 *lxdata; + Atom ltype; - lxdata = 0; - ltype = 0; - XGetWindowProperty(g_display, g_wnd, prop, 0, 0, 0, - AnyPropertyType, <ype, &lfmt, &ln_items, - &llen_after, &lxdata); - if (lxdata != 0) - { - XFree(lxdata); - } - if (ltype == 0) - { - /* XGetWindowProperty failed */ - return 1; - } + lxdata = 0; + ltype = 0; + XGetWindowProperty(g_display, g_wnd, prop, 0, 0, 0, + AnyPropertyType, <ype, &lfmt, &ln_items, + &llen_after, &lxdata); + + if (lxdata != 0) + { + XFree(lxdata); + } + + if (ltype == 0) + { + /* XGetWindowProperty failed */ + return 1; + } + + if (ltype == g_incr_atom) + { + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_property_notify: INCR start")); + g_incr_in_progress = 1; + g_incr_atom_type = prop; + g_incr_data_size = 0; + g_free(g_incr_data); + g_incr_data = 0; + XDeleteProperty(g_display, g_wnd, prop); + return 0; + } + + if (llen_after < 1) + { + /* no data, ok */ + return 0; + } + + lxdata = 0; + ltype = 0; + XGetWindowProperty(g_display, g_wnd, prop, 0, (llen_after + 3) / 4, 0, + AnyPropertyType, <ype, &lfmt, &ln_items, + &llen_after, &lxdata); + + if (ltype == 0) + { + /* XGetWindowProperty failed */ + if (lxdata != 0) + { + XFree(lxdata); + } + + return 1; + } + + lxdata_size = (lfmt / 8) * ln_items; + + if (lxdata_size < 1) + { + /* should not happen */ + if (lxdata != 0) + { + XFree(lxdata); + } + + return 2; + } + + if (llen_after > 0) + { + /* should not happen */ + if (lxdata != 0) + { + XFree(lxdata); + } + + return 3; + } + + if (xdata != 0) + { + *xdata = (char *)g_malloc(lxdata_size, 0); + g_memcpy(*xdata, lxdata, lxdata_size); + } + + if (lxdata != 0) + { + XFree(lxdata); + } + + if (xdata_size != 0) + { + *xdata_size = lxdata_size; + } + + if (fmt != 0) + { + *fmt = (int)lfmt; + } + + if (n_items != 0) + { + *n_items = (int)ln_items; + } + + if (type != 0) + { + *type = ltype; + } - if (ltype == g_incr_atom) - { - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_property_notify: INCR start")); - g_incr_in_progress = 1; - g_incr_atom_type = prop; - g_incr_data_size = 0; - g_free(g_incr_data); - g_incr_data = 0; - XDeleteProperty(g_display, g_wnd, prop); return 0; - } - - if (llen_after < 1) - { - /* no data, ok */ - return 0; - } - lxdata = 0; - ltype = 0; - XGetWindowProperty(g_display, g_wnd, prop, 0, (llen_after + 3) / 4, 0, - AnyPropertyType, <ype, &lfmt, &ln_items, - &llen_after, &lxdata); - if (ltype == 0) - { - /* XGetWindowProperty failed */ - if (lxdata != 0) - { - XFree(lxdata); - } - return 1; - } - lxdata_size = (lfmt / 8) * ln_items; - if (lxdata_size < 1) - { - /* should not happen */ - if (lxdata != 0) - { - XFree(lxdata); - } - return 2; - } - if (llen_after > 0) - { - /* should not happen */ - if (lxdata != 0) - { - XFree(lxdata); - } - return 3; - } - if (xdata != 0) - { - *xdata = (char*)g_malloc(lxdata_size, 0); - g_memcpy(*xdata, lxdata, lxdata_size); - } - if (lxdata != 0) - { - XFree(lxdata); - } - if (xdata_size != 0) - { - *xdata_size = lxdata_size; - } - if (fmt != 0) - { - *fmt = (int)lfmt; - } - if (n_items != 0) - { - *n_items = (int)ln_items; - } - if (type != 0) - { - *type = ltype; - } - return 0; } /*****************************************************************************/ @@ -948,178 +1031,188 @@ clipboard_get_window_property(Window wnd, Atom prop, Atom* type, int* fmt, Time time; } XSelectionEvent; */ static int APP_CC -clipboard_event_selection_notify(XEvent* xevent) +clipboard_event_selection_notify(XEvent *xevent) { - XSelectionEvent* lxevent; - char* data; - int data_size; - int n_items; - int fmt; - int rv; - int index; - int convert_to_string; - int convert_to_utf8; - int convert_to_bmp_image; - int send_format_announce; - int atom; - Atom* atoms; - Atom type; - tui32 format_id; - char format_name[32]; + XSelectionEvent *lxevent; + char *data; + int data_size; + int n_items; + int fmt; + int rv; + int index; + int convert_to_string; + int convert_to_utf8; + int convert_to_bmp_image; + int send_format_announce; + int atom; + Atom *atoms; + Atom type; + tui32 format_id; + char format_name[32]; - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify:")); - data_size = 0; - n_items = 0; - fmt = 0; - convert_to_string = 0; - convert_to_utf8 = 0; - convert_to_bmp_image = 0; - send_format_announce = 0; - format_id = 0; - rv = 0; - data = 0; - type = 0; - lxevent = (XSelectionEvent*)xevent; - g_memset(format_name, 0, 32); - if (lxevent->property == None) - { - LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: clip could " - "not be converted")); - rv = 1; - } - if (rv == 0) - { - /* we need this if the call below turns out to be a - clipboard INCR operation */ - if (!g_incr_in_progress) + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify:")); + data_size = 0; + n_items = 0; + fmt = 0; + convert_to_string = 0; + convert_to_utf8 = 0; + convert_to_bmp_image = 0; + send_format_announce = 0; + format_id = 0; + rv = 0; + data = 0; + type = 0; + lxevent = (XSelectionEvent *)xevent; + g_memset(format_name, 0, 32); + + if (lxevent->property == None) { - g_incr_atom_target = lxevent->target; + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: clip could " + "not be converted")); + rv = 1; } - rv = clipboard_get_window_property(lxevent->requestor, lxevent->property, - &type, &fmt, - &n_items, &data, &data_size); - if (rv != 0) + if (rv == 0) { - LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: " - "clipboard_get_window_property failed error %d", rv)); - } - XDeleteProperty(g_display, lxevent->requestor, lxevent->property); - } - if (rv == 0) - { - if (lxevent->selection == g_clipboard_atom) - { - if (lxevent->target == g_targets_atom) - { - /* on a 64 bit machine, actual_format_return of 32 implies long */ - if ((type == XA_ATOM) && (fmt == 32)) + /* we need this if the call below turns out to be a + clipboard INCR operation */ + if (!g_incr_in_progress) { - atoms = (Atom*)data; - for (index = 0; index < n_items; index++) - { - atom = atoms[index]; - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: %d %s %d", - atom, XGetAtomName(g_display, atom), XA_STRING)); - if (atom == g_utf8_atom) + g_incr_atom_target = lxevent->target; + } + + rv = clipboard_get_window_property(lxevent->requestor, lxevent->property, + &type, &fmt, + &n_items, &data, &data_size); + + if (rv != 0) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: " + "clipboard_get_window_property failed error %d", rv)); + } + + XDeleteProperty(g_display, lxevent->requestor, lxevent->property); + } + + if (rv == 0) + { + if (lxevent->selection == g_clipboard_atom) + { + if (lxevent->target == g_targets_atom) { - convert_to_utf8 = 1; + /* on a 64 bit machine, actual_format_return of 32 implies long */ + if ((type == XA_ATOM) && (fmt == 32)) + { + atoms = (Atom *)data; + + for (index = 0; index < n_items; index++) + { + atom = atoms[index]; + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: %d %s %d", + atom, XGetAtomName(g_display, atom), XA_STRING)); + + if (atom == g_utf8_atom) + { + convert_to_utf8 = 1; + } + else if (atom == XA_STRING) + { + convert_to_string = 1; + } + else if (atom == g_image_bmp_atom) + { + convert_to_bmp_image = 1; + } + } + } + else + { + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: error, " + "target is 'TARGETS' and type[%d] or fmt[%d] not right, " + "should be type[%d], fmt[%d]", type, fmt, XA_ATOM, 32)); + } } - else if (atom == XA_STRING) + else if (lxevent->target == g_utf8_atom) { - convert_to_string = 1; + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: UTF8_STRING " + "data_size %d", data_size)); + g_free(g_last_clip_data); + g_last_clip_data = 0; + g_last_clip_size = data_size; + g_last_clip_data = g_malloc(g_last_clip_size + 1, 0); + g_last_clip_type = g_utf8_atom; + g_memcpy(g_last_clip_data, data, g_last_clip_size); + g_last_clip_data[g_last_clip_size] = 0; + send_format_announce = 1; + format_id = CB_FORMAT_UNICODETEXT; } - else if (atom == g_image_bmp_atom) + else if (lxevent->target == XA_STRING) { - convert_to_bmp_image = 1; + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: XA_STRING " + "data_size %d", data_size)); + g_free(g_last_clip_data); + g_last_clip_data = 0; + g_last_clip_size = data_size; + g_last_clip_data = g_malloc(g_last_clip_size + 1, 0); + g_last_clip_type = XA_STRING; + g_memcpy(g_last_clip_data, data, g_last_clip_size); + g_last_clip_data[g_last_clip_size] = 0; + send_format_announce = 1; + format_id = CB_FORMAT_UNICODETEXT; + } + else if (lxevent->target == g_image_bmp_atom) + { + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: image/bmp " + "data_size %d", data_size)); + g_free(g_last_clip_data); + g_last_clip_data = 0; + g_last_clip_size = data_size; + g_last_clip_data = g_malloc(data_size, 0); + g_last_clip_type = g_image_bmp_atom; + g_memcpy(g_last_clip_data, data, data_size); + send_format_announce = 1; + format_id = CB_FORMAT_DIB; + g_strcpy(format_name, "image/bmp"); + } + else + { + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: " + "unknown target")); } - } } else { - LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: error, " - "target is 'TARGETS' and type[%d] or fmt[%d] not right, " - "should be type[%d], fmt[%d]", type, fmt, XA_ATOM, 32)); + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: " + "unknown selection")); } - } - else if (lxevent->target == g_utf8_atom) - { - LOGM((LOG_LEVEL_DEBUG,"clipboard_event_selection_notify: UTF8_STRING " - "data_size %d", data_size)); - g_free(g_last_clip_data); - g_last_clip_data = 0; - g_last_clip_size = data_size; - g_last_clip_data = g_malloc(g_last_clip_size + 1, 0); - g_last_clip_type = g_utf8_atom; - g_memcpy(g_last_clip_data, data, g_last_clip_size); - g_last_clip_data[g_last_clip_size] = 0; - send_format_announce = 1; - format_id = CB_FORMAT_UNICODETEXT; - } - else if (lxevent->target == XA_STRING) - { - LOGM((LOG_LEVEL_DEBUG,"clipboard_event_selection_notify: XA_STRING " - "data_size %d", data_size)); - g_free(g_last_clip_data); - g_last_clip_data = 0; - g_last_clip_size = data_size; - g_last_clip_data = g_malloc(g_last_clip_size + 1, 0); - g_last_clip_type = XA_STRING; - g_memcpy(g_last_clip_data, data, g_last_clip_size); - g_last_clip_data[g_last_clip_size] = 0; - send_format_announce = 1; - format_id = CB_FORMAT_UNICODETEXT; - } - else if (lxevent->target == g_image_bmp_atom) - { - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_notify: image/bmp " - "data_size %d", data_size)); - g_free(g_last_clip_data); - g_last_clip_data = 0; - g_last_clip_size = data_size; - g_last_clip_data = g_malloc(data_size, 0); - g_last_clip_type = g_image_bmp_atom; - g_memcpy(g_last_clip_data, data, data_size); - send_format_announce = 1; - format_id = CB_FORMAT_DIB; - g_strcpy(format_name, "image/bmp"); - } - else - { - LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_notify: " - "unknown target")); - } } - else + + if (convert_to_utf8) { - LOGM((LOG_LEVEL_ERROR,"clipboard_event_selection_notify: " - "unknown selection")); + XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom, + g_clip_property_atom, g_wnd, lxevent->time); } - } - if (convert_to_utf8) - { - XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom, - g_clip_property_atom, g_wnd, lxevent->time); - } - else if (convert_to_string) - { - XConvertSelection(g_display, g_clipboard_atom, XA_STRING, - g_clip_property_atom, g_wnd, lxevent->time); - } - else if (convert_to_bmp_image) - { - XConvertSelection(g_display, g_clipboard_atom, g_image_bmp_atom, - g_clip_property_atom, g_wnd, lxevent->time); - } - if (send_format_announce) - { - if (clipboard_send_format_announce(format_id, format_name) != 0) + else if (convert_to_string) { - rv = 4; + XConvertSelection(g_display, g_clipboard_atom, XA_STRING, + g_clip_property_atom, g_wnd, lxevent->time); } - } - g_free(data); - return rv; + else if (convert_to_bmp_image) + { + XConvertSelection(g_display, g_clipboard_atom, g_image_bmp_atom, + g_clip_property_atom, g_wnd, lxevent->time); + } + + if (send_format_announce) + { + if (clipboard_send_format_announce(format_id, format_name) != 0) + { + rv = 4; + } + } + + g_free(data); + return rv; } /*****************************************************************************/ @@ -1143,113 +1236,120 @@ clipboard_event_selection_notify(XEvent* xevent) * a 32bit machine and 8 bytes on a 64 machine */ static int APP_CC -clipboard_event_selection_request(XEvent* xevent) +clipboard_event_selection_request(XEvent *xevent) { - XSelectionRequestEvent* lxev; - XEvent xev; - Atom atom_buf[10]; - Atom type; - int fmt; - int n_items; - int xdata_size; - char* xdata; + XSelectionRequestEvent *lxev; + XEvent xev; + Atom atom_buf[10]; + Atom type; + int fmt; + int n_items; + int xdata_size; + char *xdata; - lxev = (XSelectionRequestEvent*)xevent; - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: g_wnd %d, " - ".requestor %d .owner %d .selection %d '%s' .target %d .property %d", - g_wnd, lxev->requestor, lxev->owner, lxev->selection, - XGetAtomName(g_display, lxev->selection), - lxev->target, lxev->property)); - if (lxev->property == None) - { - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " - "lxev->property is None")); - } - else if (lxev->target == g_targets_atom) - { - /* requestor is asking what the selection can be converted to */ - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " - "g_targets_atom")); - atom_buf[0] = g_targets_atom; - atom_buf[1] = g_timestamp_atom; - atom_buf[2] = g_multiple_atom; - atom_buf[3] = XA_STRING; - atom_buf[4] = g_utf8_atom; - atom_buf[5] = g_image_bmp_atom; - return clipboard_provide_selection(lxev, XA_ATOM, 32, (char*)atom_buf, 6); - } - else if (lxev->target == g_timestamp_atom) - { - /* requestor is asking the time I got the selection */ - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " - "g_timestamp_atom")); - atom_buf[0] = g_selection_time; - return clipboard_provide_selection(lxev, XA_INTEGER, 32, (char*)atom_buf, 1); - } - else if (lxev->target == g_multiple_atom) - { - /* target, property pairs */ - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " - "g_multiple_atom")); - if (clipboard_get_window_property(xev.xselection.requestor, - xev.xselection.property, - &type, &fmt, &n_items, &xdata, - &xdata_size) == 0) + lxev = (XSelectionRequestEvent *)xevent; + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: g_wnd %d, " + ".requestor %d .owner %d .selection %d '%s' .target %d .property %d", + g_wnd, lxev->requestor, lxev->owner, lxev->selection, + XGetAtomName(g_display, lxev->selection), + lxev->target, lxev->property)); + + if (lxev->property == None) { - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: g_multiple_atom " - "n_items %d", n_items)); - /* todo */ - g_free(xdata); + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " + "lxev->property is None")); } - } - else if ((lxev->target == XA_STRING) || (lxev->target == g_utf8_atom)) - { - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: %s", - XGetAtomName(g_display, lxev->target))); - clipboard_format_id = CB_FORMAT_UNICODETEXT; - if (g_data_in_up_to_date) + else if (lxev->target == g_targets_atom) { - return clipboard_provide_selection(lxev, lxev->target, 8, - g_data_in, g_strlen(g_data_in)); + /* requestor is asking what the selection can be converted to */ + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " + "g_targets_atom")); + atom_buf[0] = g_targets_atom; + atom_buf[1] = g_timestamp_atom; + atom_buf[2] = g_multiple_atom; + atom_buf[3] = XA_STRING; + atom_buf[4] = g_utf8_atom; + atom_buf[5] = g_image_bmp_atom; + return clipboard_provide_selection(lxev, XA_ATOM, 32, (char *)atom_buf, 6); } - if (g_selection_request_event_count > 10) + else if (lxev->target == g_timestamp_atom) { - LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_request: error, " - "too many requests")); + /* requestor is asking the time I got the selection */ + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " + "g_timestamp_atom")); + atom_buf[0] = g_selection_time; + return clipboard_provide_selection(lxev, XA_INTEGER, 32, (char *)atom_buf, 1); + } + else if (lxev->target == g_multiple_atom) + { + /* target, property pairs */ + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: " + "g_multiple_atom")); + + if (clipboard_get_window_property(xev.xselection.requestor, + xev.xselection.property, + &type, &fmt, &n_items, &xdata, + &xdata_size) == 0) + { + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: g_multiple_atom " + "n_items %d", n_items)); + /* todo */ + g_free(xdata); + } + } + else if ((lxev->target == XA_STRING) || (lxev->target == g_utf8_atom)) + { + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_request: %s", + XGetAtomName(g_display, lxev->target))); + clipboard_format_id = CB_FORMAT_UNICODETEXT; + + if (g_data_in_up_to_date) + { + return clipboard_provide_selection(lxev, lxev->target, 8, + g_data_in, g_strlen(g_data_in)); + } + + if (g_selection_request_event_count > 10) + { + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_request: error, " + "too many requests")); + } + else + { + g_memcpy(&(g_selection_request_event[g_selection_request_event_count]), + lxev, sizeof(g_selection_request_event[0])); + + if (g_selection_request_event_count == 0) + { + clipboard_send_data_request(); + g_waiting_for_data_response = 1; + g_waiting_for_data_response_time = xcommon_get_local_time(); + } + + g_selection_request_event_count++; + return 0; + } + } + else if (lxev->target == g_image_bmp_atom) + { + g_memcpy(&g_saved_selection_req_event, lxev, + sizeof(g_saved_selection_req_event)); + g_last_clip_type = g_image_bmp_atom; + g_want_image_data = 1; + clipboard_format_id = CB_FORMAT_DIB; + clipboard_send_data_request(); + g_waiting_for_data_response = 1; + g_waiting_for_data_response_time = clipboard_get_local_time(); + return 0; } else { - g_memcpy(&(g_selection_request_event[g_selection_request_event_count]), - lxev, sizeof(g_selection_request_event[0])); - if (g_selection_request_event_count == 0) - { - clipboard_send_data_request(); - g_waiting_for_data_response = 1; - g_waiting_for_data_response_time = xcommon_get_local_time(); - } - g_selection_request_event_count++; - return 0; + LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_request: unknown " + "target %s", XGetAtomName(g_display, lxev->target))); } - } - else if (lxev->target == g_image_bmp_atom) - { - g_memcpy(&g_saved_selection_req_event, lxev, - sizeof(g_saved_selection_req_event)); - g_last_clip_type = g_image_bmp_atom; - g_want_image_data = 1; - clipboard_format_id = CB_FORMAT_DIB; - clipboard_send_data_request(); - g_waiting_for_data_response = 1; - g_waiting_for_data_response_time = clipboard_get_local_time(); + + clipboard_refuse_selection(lxev); return 0; - } - else - { - LOGM((LOG_LEVEL_ERROR,"clipboard_event_selection_request: unknown " - "target %s", XGetAtomName(g_display, lxev->target))); - } - clipboard_refuse_selection(lxev); - return 0; } /*****************************************************************************/ @@ -1265,10 +1365,10 @@ clipboard_event_selection_request(XEvent* xevent) Time time; } XSelectionClearEvent; */ static int APP_CC -clipboard_event_selection_clear(XEvent* xevent) +clipboard_event_selection_clear(XEvent *xevent) { - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_clear:")); - return 0; + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_selection_clear:")); + return 0; } /*****************************************************************************/ @@ -1284,134 +1384,153 @@ clipboard_event_selection_clear(XEvent* xevent) int state; // PropertyNewValue or PropertyDelete } XPropertyEvent; */ static int APP_CC -clipboard_event_property_notify(XEvent* xevent) +clipboard_event_property_notify(XEvent *xevent) { - Atom actual_type_return; - int actual_format_return; - unsigned long nitems_returned; - unsigned long bytes_left; - unsigned char* data; - int rv; - int format_in_bytes; - int new_data_len; - char* cptr; - char format_name[32]; + Atom actual_type_return; + int actual_format_return; + unsigned long nitems_returned; + unsigned long bytes_left; + unsigned char *data; + int rv; + int format_in_bytes; + int new_data_len; + char *cptr; + char format_name[32]; - LOG(10, ("clipboard_check_wait_objs: PropertyNotify .window %d " - ".state %d .atom %d", xevent->xproperty.window, - xevent->xproperty.state, xevent->xproperty.atom)); - if (g_incr_in_progress && - (xevent->xproperty.atom == g_incr_atom_type) && - (xevent->xproperty.state == PropertyNewValue)) - { - rv = XGetWindowProperty(g_display, g_wnd, g_incr_atom_type, 0, 0, 0, - AnyPropertyType, &actual_type_return, &actual_format_return, - &nitems_returned, &bytes_left, (unsigned char **) &data); - if (data != 0) - { - XFree(data); - data = 0; - } - if (bytes_left <= 0) - { - LOGM((LOG_LEVEL_DEBUG, "clipboard_event_property_notify: INCR done")); - g_memset(format_name, 0, 32); - /* clipboard INCR cycle has completed */ - g_incr_in_progress = 0; - g_last_clip_size = g_incr_data_size; - g_last_clip_data = g_incr_data; - g_incr_data = 0; - g_last_clip_type = g_incr_atom_target; - if (g_incr_atom_target == g_image_bmp_atom) - { - g_snprintf(format_name, 31, "image/bmp"); - clipboard_send_format_announce(CB_FORMAT_DIB, format_name); - } - XDeleteProperty(g_display, g_wnd, g_incr_atom_type); - } - else - { - rv = XGetWindowProperty(g_display, g_wnd, g_incr_atom_type, 0, bytes_left, 0, - AnyPropertyType, &actual_type_return, &actual_format_return, - &nitems_returned, &bytes_left, (unsigned char **) &data); + LOG(10, ("clipboard_check_wait_objs: PropertyNotify .window %d " + ".state %d .atom %d", xevent->xproperty.window, + xevent->xproperty.state, xevent->xproperty.atom)); + + if (g_incr_in_progress && + (xevent->xproperty.atom == g_incr_atom_type) && + (xevent->xproperty.state == PropertyNewValue)) + { + rv = XGetWindowProperty(g_display, g_wnd, g_incr_atom_type, 0, 0, 0, + AnyPropertyType, &actual_type_return, &actual_format_return, + &nitems_returned, &bytes_left, (unsigned char **) &data); - format_in_bytes = actual_format_return / 8; - if ((actual_format_return == 32) && (sizeof(long) == 8)) - { - /* on a 64 bit machine, actual_format_return of 32 implies long */ - format_in_bytes = 8; - } - new_data_len = nitems_returned * format_in_bytes; - cptr = (char*)g_malloc(g_incr_data_size + new_data_len, 0); - g_memcpy(cptr, g_incr_data, g_incr_data_size); - g_free(g_incr_data); - if (cptr == NULL) - { - g_incr_data = 0; - /* cannot add any more data */ if (data != 0) { - XFree(data); + XFree(data); + data = 0; + } + + if (bytes_left <= 0) + { + LOGM((LOG_LEVEL_DEBUG, "clipboard_event_property_notify: INCR done")); + g_memset(format_name, 0, 32); + /* clipboard INCR cycle has completed */ + g_incr_in_progress = 0; + g_last_clip_size = g_incr_data_size; + g_last_clip_data = g_incr_data; + g_incr_data = 0; + g_last_clip_type = g_incr_atom_target; + + if (g_incr_atom_target == g_image_bmp_atom) + { + g_snprintf(format_name, 31, "image/bmp"); + clipboard_send_format_announce(CB_FORMAT_DIB, format_name); + } + + XDeleteProperty(g_display, g_wnd, g_incr_atom_type); + } + else + { + rv = XGetWindowProperty(g_display, g_wnd, g_incr_atom_type, 0, bytes_left, 0, + AnyPropertyType, &actual_type_return, &actual_format_return, + &nitems_returned, &bytes_left, (unsigned char **) &data); + + format_in_bytes = actual_format_return / 8; + + if ((actual_format_return == 32) && (sizeof(long) == 8)) + { + /* on a 64 bit machine, actual_format_return of 32 implies long */ + format_in_bytes = 8; + } + + new_data_len = nitems_returned * format_in_bytes; + cptr = (char *)g_malloc(g_incr_data_size + new_data_len, 0); + g_memcpy(cptr, g_incr_data, g_incr_data_size); + g_free(g_incr_data); + + if (cptr == NULL) + { + g_incr_data = 0; + + /* cannot add any more data */ + if (data != 0) + { + XFree(data); + } + + XDeleteProperty(g_display, g_wnd, g_incr_atom_type); + return 0; + } + + g_incr_data = cptr; + g_memcpy(g_incr_data + g_incr_data_size, data, new_data_len); + g_incr_data_size += new_data_len; + + if (data) + { + XFree(data); + } + + XDeleteProperty(g_display, g_wnd, g_incr_atom_type); } - XDeleteProperty(g_display, g_wnd, g_incr_atom_type); - return 0; - } - g_incr_data = cptr; - g_memcpy(g_incr_data + g_incr_data_size, data, new_data_len); - g_incr_data_size += new_data_len; - if (data) - { - XFree(data); - } - XDeleteProperty(g_display, g_wnd, g_incr_atom_type); } - } - return 0; + + return 0; } /*****************************************************************************/ /* returns 0, event handled, 1 unhandled */ int APP_CC -clipboard_xevent(void* xevent) +clipboard_xevent(void *xevent) { - XEvent* lxevent; + XEvent *lxevent; - if (!g_clip_up) - { - return 1; - } - lxevent = (XEvent*)xevent; - switch (lxevent->type) - { - case SelectionNotify: - clipboard_event_selection_notify(lxevent); - break; - case SelectionRequest: - clipboard_event_selection_request(lxevent); - break; - case SelectionClear: - clipboard_event_selection_clear(lxevent); - break; - case MappingNotify: - break; - case PropertyNotify: - clipboard_event_property_notify(lxevent); - break; - case UnmapNotify: - LOG(0, ("chansrv::clipboard_xevent: got UnmapNotify")); - break; - case ClientMessage: - LOG(0, ("chansrv::clipboard_xevent: got ClientMessage")); - break; - default: - if (lxevent->type == g_xfixes_event_base + - XFixesSetSelectionOwnerNotify) - { - clipboard_event_selection_owner_notify(lxevent); - break; - } - /* we didn't handle this message */ - return 1; - } - return 0; + if (!g_clip_up) + { + return 1; + } + + lxevent = (XEvent *)xevent; + + switch (lxevent->type) + { + case SelectionNotify: + clipboard_event_selection_notify(lxevent); + break; + case SelectionRequest: + clipboard_event_selection_request(lxevent); + break; + case SelectionClear: + clipboard_event_selection_clear(lxevent); + break; + case MappingNotify: + break; + case PropertyNotify: + clipboard_event_property_notify(lxevent); + break; + case UnmapNotify: + LOG(0, ("chansrv::clipboard_xevent: got UnmapNotify")); + break; + case ClientMessage: + LOG(0, ("chansrv::clipboard_xevent: got ClientMessage")); + break; + default: + + if (lxevent->type == g_xfixes_event_base + + XFixesSetSelectionOwnerNotify) + { + clipboard_event_selection_owner_notify(lxevent); + break; + } + + /* we didn't handle this message */ + return 1; + } + + return 0; } diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index dd244572..e6407211 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -26,34 +26,34 @@ extern int g_rdpdr_chan_id; /* in chansrv.c */ int APP_CC dev_redir_init(void) { - return 0; + return 0; } /*****************************************************************************/ int APP_CC dev_redir_deinit(void) { - return 0; + return 0; } /*****************************************************************************/ int APP_CC -dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, int length, +dev_redir_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) { - return 0; + return 0; } /*****************************************************************************/ int APP_CC -dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout) +dev_redir_get_wait_objs(tbus *objs, int *count, int *timeout) { - return 0; + return 0; } /*****************************************************************************/ int APP_CC dev_redir_check_wait_objs(void) { - return 0; + return 0; } diff --git a/sesman/chansrv/rail.c b/sesman/chansrv/rail.c index 6b47f867..1ea8d73a 100644 --- a/sesman/chansrv/rail.c +++ b/sesman/chansrv/rail.c @@ -31,13 +31,13 @@ extern int g_rail_chan_id; /* in chansrv.c */ extern int g_display_num; /* in chansrv.c */ -extern char* g_exec_name; /* in chansrv.c */ +extern char *g_exec_name; /* in chansrv.c */ extern tbus g_exec_event; /* in chansrv.c */ extern tbus g_exec_mutex; /* in chansrv.c */ extern tbus g_exec_sem; /* in chansrv.c */ -extern Display* g_display; /* in xcommon.c */ -extern Screen* g_screen; /* in xcommon.c */ +extern Display *g_display; /* in xcommon.c */ +extern Screen *g_screen; /* in xcommon.c */ extern Window g_root_window; /* in xcommon.c */ extern Atom g_wm_delete_window_atom; /* in xcommon.c */ extern Atom g_wm_protocols_atom; /* in xcommon.c */ @@ -105,573 +105,597 @@ static int g_rail_running = 1; static int APP_CC is_window_valid_child_of_root(unsigned int window_id) { - int found; - unsigned int i; - unsigned int nchild; - Window r; - Window p; - Window* children; + int found; + unsigned int i; + unsigned int nchild; + Window r; + Window p; + Window *children; - found = 0; - XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); - for (i = 0; i < nchild; i++) - { - if (window_id == children[i]) + found = 0; + XQueryTree(g_display, g_root_window, &r, &p, &children, &nchild); + + for (i = 0; i < nchild; i++) { - found = 1; - break; + if (window_id == children[i]) + { + found = 1; + break; + } } - } - XFree(children); - return found; + + XFree(children); + return found; } /*****************************************************************************/ static int APP_CC rail_send_init(void) { - struct stream* s; - int bytes; - char* size_ptr; + struct stream *s; + int bytes; + char *size_ptr; - LOG(10, ("chansrv::rail_send_init:")); - make_stream(s); - init_stream(s, 8182); - out_uint16_le(s, TS_RAIL_ORDER_HANDSHAKE); - size_ptr = s->p; - out_uint16_le(s, 0); /* size, set later */ - out_uint32_le(s, 1); /* build number */ - s_mark_end(s); - bytes = (int)((s->end - s->data) - 4); - size_ptr[0] = bytes; - size_ptr[1] = bytes >> 8; - bytes = (int)(s->end - s->data); - send_channel_data(g_rail_chan_id, s->data, bytes); - free_stream(s); - return 0; + LOG(10, ("chansrv::rail_send_init:")); + make_stream(s); + init_stream(s, 8182); + out_uint16_le(s, TS_RAIL_ORDER_HANDSHAKE); + size_ptr = s->p; + out_uint16_le(s, 0); /* size, set later */ + out_uint32_le(s, 1); /* build number */ + s_mark_end(s); + bytes = (int)((s->end - s->data) - 4); + size_ptr[0] = bytes; + size_ptr[1] = bytes >> 8; + bytes = (int)(s->end - s->data); + send_channel_data(g_rail_chan_id, s->data, bytes); + free_stream(s); + return 0; } /******************************************************************************/ static int DEFAULT_CC -anotherWMRunning(Display* display, XErrorEvent* xe) +anotherWMRunning(Display *display, XErrorEvent *xe) { - g_rail_running = 0; - return -1; + g_rail_running = 0; + return -1; } /******************************************************************************/ static int APP_CC rail_is_another_wm_running(void) { - XErrorHandler old; + XErrorHandler old; - g_rail_running = 1; - old = XSetErrorHandler((XErrorHandler)anotherWMRunning); - XSelectInput(g_display, g_root_window, - PropertyChangeMask | StructureNotifyMask | - SubstructureRedirectMask | ButtonPressMask | - SubstructureNotifyMask | FocusChangeMask | - EnterWindowMask | LeaveWindowMask); - XSync(g_display, 0); - XSetErrorHandler((XErrorHandler)old); - g_rail_up = g_rail_running; - if (!g_rail_up) - { - return 1; - } - return 0; + g_rail_running = 1; + old = XSetErrorHandler((XErrorHandler)anotherWMRunning); + XSelectInput(g_display, g_root_window, + PropertyChangeMask | StructureNotifyMask | + SubstructureRedirectMask | ButtonPressMask | + SubstructureNotifyMask | FocusChangeMask | + EnterWindowMask | LeaveWindowMask); + XSync(g_display, 0); + XSetErrorHandler((XErrorHandler)old); + g_rail_up = g_rail_running; + + if (!g_rail_up) + { + return 1; + } + + return 0; } /*****************************************************************************/ int APP_CC rail_init(void) { - LOG(10, ("chansrv::rail_init:")); - xcommon_init(); - if (rail_is_another_wm_running()) - { - log_message(LOG_LEVEL_ERROR, "rail_init: another window manager " - "is running"); - } - rail_send_init(); - g_rail_up = 1; - return 0; + LOG(10, ("chansrv::rail_init:")); + xcommon_init(); + + if (rail_is_another_wm_running()) + { + log_message(LOG_LEVEL_ERROR, "rail_init: another window manager " + "is running"); + } + + rail_send_init(); + g_rail_up = 1; + return 0; } /*****************************************************************************/ int APP_CC rail_deinit(void) { - if (g_rail_up) - { - /* no longer window manager */ - XSelectInput(g_display, g_root_window, 0); - g_rail_up = 0; - } - return 0; -} - -/*****************************************************************************/ -static char* APP_CC -read_uni(struct stream* s, int num_chars) -{ - twchar* rchrs; - char* rv; - int index; - int lchars; - - rchrs = 0; - rv = 0; - if (num_chars > 0) - { - rchrs = (twchar*)g_malloc((num_chars + 1) * sizeof(twchar), 0); - for (index = 0; index < num_chars; index++) + if (g_rail_up) { - in_uint16_le(s, rchrs[index]); + /* no longer window manager */ + XSelectInput(g_display, g_root_window, 0); + g_rail_up = 0; } - rchrs[num_chars] = 0; - lchars = g_wcstombs(0, rchrs, 0); - if (lchars > 0) + + return 0; +} + +/*****************************************************************************/ +static char *APP_CC +read_uni(struct stream *s, int num_chars) +{ + twchar *rchrs; + char *rv; + int index; + int lchars; + + rchrs = 0; + rv = 0; + + if (num_chars > 0) { - rv = (char*)g_malloc((lchars + 1) * 4, 0); - g_wcstombs(rv, rchrs, lchars); - rv[lchars] = 0; + rchrs = (twchar *)g_malloc((num_chars + 1) * sizeof(twchar), 0); + + for (index = 0; index < num_chars; index++) + { + in_uint16_le(s, rchrs[index]); + } + + rchrs[num_chars] = 0; + lchars = g_wcstombs(0, rchrs, 0); + + if (lchars > 0) + { + rv = (char *)g_malloc((lchars + 1) * 4, 0); + g_wcstombs(rv, rchrs, lchars); + rv[lchars] = 0; + } } - } - g_free(rchrs); - return rv; + + g_free(rchrs); + return rv; } /*****************************************************************************/ static int APP_CC -rail_process_exec(struct stream* s, int size) +rail_process_exec(struct stream *s, int size) { - int pid; - int flags; - int ExeOrFileLength; - int WorkingDirLength; - int ArgumentsLen; - char* ExeOrFile; - char* WorkingDir; - char* Arguments; + int pid; + int flags; + int ExeOrFileLength; + int WorkingDirLength; + int ArgumentsLen; + char *ExeOrFile; + char *WorkingDir; + char *Arguments; - LOG(0, ("chansrv::rail_process_exec:")); - in_uint16_le(s, flags); - in_uint16_le(s, ExeOrFileLength); - in_uint16_le(s, WorkingDirLength); - in_uint16_le(s, ArgumentsLen); - ExeOrFile = read_uni(s, ExeOrFileLength); - WorkingDir = read_uni(s, WorkingDirLength); - Arguments = read_uni(s, ArgumentsLen); - LOG(10, (" flags 0x%8.8x ExeOrFileLength %d WorkingDirLength %d " - "ArgumentsLen %d ExeOrFile [%s] WorkingDir [%s] " - "Arguments [%s]", flags, ExeOrFileLength, WorkingDirLength, - ArgumentsLen, ExeOrFile, WorkingDir, Arguments)); - if (g_strlen(ExeOrFile) > 0) - { - LOG(10, ("rail_process_exec: pre")); - /* ask main thread to fork */ - tc_mutex_lock(g_exec_mutex); - g_exec_name = ExeOrFile; - g_set_wait_obj(g_exec_event); - tc_sem_dec(g_exec_sem); - tc_mutex_unlock(g_exec_mutex); - LOG(10, ("rail_process_exec: post")); - } - g_free(ExeOrFile); - g_free(WorkingDir); - g_free(Arguments); - return 0; + LOG(0, ("chansrv::rail_process_exec:")); + in_uint16_le(s, flags); + in_uint16_le(s, ExeOrFileLength); + in_uint16_le(s, WorkingDirLength); + in_uint16_le(s, ArgumentsLen); + ExeOrFile = read_uni(s, ExeOrFileLength); + WorkingDir = read_uni(s, WorkingDirLength); + Arguments = read_uni(s, ArgumentsLen); + LOG(10, (" flags 0x%8.8x ExeOrFileLength %d WorkingDirLength %d " + "ArgumentsLen %d ExeOrFile [%s] WorkingDir [%s] " + "Arguments [%s]", flags, ExeOrFileLength, WorkingDirLength, + ArgumentsLen, ExeOrFile, WorkingDir, Arguments)); + + if (g_strlen(ExeOrFile) > 0) + { + LOG(10, ("rail_process_exec: pre")); + /* ask main thread to fork */ + tc_mutex_lock(g_exec_mutex); + g_exec_name = ExeOrFile; + g_set_wait_obj(g_exec_event); + tc_sem_dec(g_exec_sem); + tc_mutex_unlock(g_exec_mutex); + LOG(10, ("rail_process_exec: post")); + } + + g_free(ExeOrFile); + g_free(WorkingDir); + g_free(Arguments); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_activate(struct stream* s, int size) +rail_process_activate(struct stream *s, int size) { - int window_id; - int enabled; + int window_id; + int enabled; - LOG(10, ("chansrv::rail_process_activate:")); - in_uint32_le(s, window_id); - in_uint8(s, enabled); - LOG(10, (" window_id 0x%8.8x enabled %d", window_id, enabled)); - if (enabled) - { - LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); - XRaiseWindow(g_display, window_id); - LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); - XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); - } - return 0; + LOG(10, ("chansrv::rail_process_activate:")); + in_uint32_le(s, window_id); + in_uint8(s, enabled); + LOG(10, (" window_id 0x%8.8x enabled %d", window_id, enabled)); + + if (enabled) + { + LOG(10, ("chansrv::rail_process_activate: calling XRaiseWindow 0x%8.8x", window_id)); + XRaiseWindow(g_display, window_id); + LOG(10, ("chansrv::rail_process_activate: calling XSetInputFocus 0x%8.8x", window_id)); + XSetInputFocus(g_display, window_id, RevertToParent, CurrentTime); + } + + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_system_param(struct stream* s, int size) +rail_process_system_param(struct stream *s, int size) { - int system_param; + int system_param; - LOG(10, ("chansrv::rail_process_system_param:")); - in_uint32_le(s, system_param); - LOG(10, (" system_param 0x%8.8x", system_param)); - return 0; + LOG(10, ("chansrv::rail_process_system_param:")); + in_uint32_le(s, system_param); + LOG(10, (" system_param 0x%8.8x", system_param)); + return 0; } /******************************************************************************/ static int APP_CC rail_close_window(int window_id) { - XEvent ce; + XEvent ce; - LOG(0, ("chansrv::rail_close_window:")); - g_memset(&ce, 0, sizeof(ce)); - ce.xclient.type = ClientMessage; - ce.xclient.message_type = g_wm_protocols_atom; - ce.xclient.display = g_display; - ce.xclient.window = window_id; - ce.xclient.format = 32; - ce.xclient.data.l[0] = g_wm_delete_window_atom; - ce.xclient.data.l[1] = CurrentTime; - XSendEvent(g_display, window_id, False, NoEventMask, &ce); - return 0; + LOG(0, ("chansrv::rail_close_window:")); + g_memset(&ce, 0, sizeof(ce)); + ce.xclient.type = ClientMessage; + ce.xclient.message_type = g_wm_protocols_atom; + ce.xclient.display = g_display; + ce.xclient.window = window_id; + ce.xclient.format = 32; + ce.xclient.data.l[0] = g_wm_delete_window_atom; + ce.xclient.data.l[1] = CurrentTime; + XSendEvent(g_display, window_id, False, NoEventMask, &ce); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_system_command(struct stream* s, int size) +rail_process_system_command(struct stream *s, int size) { - int window_id; - int command; + int window_id; + int command; - LOG(10, ("chansrv::rail_process_system_command:")); - in_uint32_le(s, window_id); - in_uint16_le(s, command); - switch (command) - { - case SC_SIZE: - LOG(10, (" window_id 0x%8.8x SC_SIZE", window_id)); - break; - case SC_MOVE: - LOG(10, (" window_id 0x%8.8x SC_MOVE", window_id)); - break; - case SC_MINIMIZE: - LOG(10, (" window_id 0x%8.8x SC_MINIMIZE", window_id)); - break; - case SC_MAXIMIZE: - LOG(10, (" window_id 0x%8.8x SC_MAXIMIZE", window_id)); - break; - case SC_CLOSE: - LOG(10, (" window_id 0x%8.8x SC_CLOSE", window_id)); - rail_close_window(window_id); - break; - case SC_KEYMENU: - LOG(10, (" window_id 0x%8.8x SC_KEYMENU", window_id)); - break; - case SC_RESTORE: - LOG(10, (" window_id 0x%8.8x SC_RESTORE", window_id)); - break; - case SC_DEFAULT: - LOG(10, (" window_id 0x%8.8x SC_DEFAULT", window_id)); - break; - default: - LOG(10, (" window_id 0x%8.8x unknown command command %d", - window_id, command)); - break; - } - return 0; + LOG(10, ("chansrv::rail_process_system_command:")); + in_uint32_le(s, window_id); + in_uint16_le(s, command); + + switch (command) + { + case SC_SIZE: + LOG(10, (" window_id 0x%8.8x SC_SIZE", window_id)); + break; + case SC_MOVE: + LOG(10, (" window_id 0x%8.8x SC_MOVE", window_id)); + break; + case SC_MINIMIZE: + LOG(10, (" window_id 0x%8.8x SC_MINIMIZE", window_id)); + break; + case SC_MAXIMIZE: + LOG(10, (" window_id 0x%8.8x SC_MAXIMIZE", window_id)); + break; + case SC_CLOSE: + LOG(10, (" window_id 0x%8.8x SC_CLOSE", window_id)); + rail_close_window(window_id); + break; + case SC_KEYMENU: + LOG(10, (" window_id 0x%8.8x SC_KEYMENU", window_id)); + break; + case SC_RESTORE: + LOG(10, (" window_id 0x%8.8x SC_RESTORE", window_id)); + break; + case SC_DEFAULT: + LOG(10, (" window_id 0x%8.8x SC_DEFAULT", window_id)); + break; + default: + LOG(10, (" window_id 0x%8.8x unknown command command %d", + window_id, command)); + break; + } + + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_handshake(struct stream* s, int size) +rail_process_handshake(struct stream *s, int size) { - int build_number; + int build_number; - LOG(10, ("chansrv::rail_process_handshake:")); - in_uint32_le(s, build_number); - LOG(10, (" build_number 0x%8.8x", build_number)); - return 0; + LOG(10, ("chansrv::rail_process_handshake:")); + in_uint32_le(s, build_number); + LOG(10, (" build_number 0x%8.8x", build_number)); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_notify_event(struct stream* s, int size) +rail_process_notify_event(struct stream *s, int size) { - int window_id; - int notify_id; - int message; + int window_id; + int notify_id; + int message; - LOG(10, ("chansrv::rail_process_notify_event:")); - in_uint32_le(s, window_id); - in_uint32_le(s, notify_id); - in_uint32_le(s, message); - LOG(10, (" window_id 0x%8.8x notify_id 0x%8.8x message 0x%8.8x", - window_id, notify_id, message)); - return 0; + LOG(10, ("chansrv::rail_process_notify_event:")); + in_uint32_le(s, window_id); + in_uint32_le(s, notify_id); + in_uint32_le(s, message); + LOG(10, (" window_id 0x%8.8x notify_id 0x%8.8x message 0x%8.8x", + window_id, notify_id, message)); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_window_move(struct stream* s, int size) +rail_process_window_move(struct stream *s, int size) { - int window_id; - int left; - int top; - int right; - int bottom; + int window_id; + int left; + int top; + int right; + int bottom; - LOG(10, ("chansrv::rail_process_window_move:")); - in_uint32_le(s, window_id); - in_uint16_le(s, left); - in_uint16_le(s, top); - in_uint16_le(s, right); - in_uint16_le(s, bottom); - LOG(10, (" window_id 0x%8.8x left %d top %d right %d bottom %d width %d height %d", - window_id, left, top, right, bottom, right - left, bottom - top)); - XMoveResizeWindow(g_display, window_id, left, top, right - left, bottom - top); - return 0; + LOG(10, ("chansrv::rail_process_window_move:")); + in_uint32_le(s, window_id); + in_uint16_le(s, left); + in_uint16_le(s, top); + in_uint16_le(s, right); + in_uint16_le(s, bottom); + LOG(10, (" window_id 0x%8.8x left %d top %d right %d bottom %d width %d height %d", + window_id, left, top, right, bottom, right - left, bottom - top)); + XMoveResizeWindow(g_display, window_id, left, top, right - left, bottom - top); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_local_move_size(struct stream* s, int size) +rail_process_local_move_size(struct stream *s, int size) { - int window_id; - int is_move_size_start; - int move_size_type; - int pos_x; - int pos_y; + int window_id; + int is_move_size_start; + int move_size_type; + int pos_x; + int pos_y; - LOG(10, ("chansrv::rail_process_local_move_size:")); - in_uint32_le(s, window_id); - in_uint16_le(s, is_move_size_start); - in_uint16_le(s, move_size_type); - in_uint16_le(s, pos_x); - in_uint16_le(s, pos_y); - LOG(10, (" window_id 0x%8.8x is_move_size_start %d move_size_type %d " - "pos_x %d pos_y %d", window_id, is_move_size_start, move_size_type, - pos_x, pos_y)); - return 0; + LOG(10, ("chansrv::rail_process_local_move_size:")); + in_uint32_le(s, window_id); + in_uint16_le(s, is_move_size_start); + in_uint16_le(s, move_size_type); + in_uint16_le(s, pos_x); + in_uint16_le(s, pos_y); + LOG(10, (" window_id 0x%8.8x is_move_size_start %d move_size_type %d " + "pos_x %d pos_y %d", window_id, is_move_size_start, move_size_type, + pos_x, pos_y)); + return 0; } /*****************************************************************************/ /* server to client only */ static int APP_CC -rail_process_min_max_info(struct stream* s, int size) +rail_process_min_max_info(struct stream *s, int size) { - LOG(10, ("chansrv::rail_process_min_max_info:")); - return 0; + LOG(10, ("chansrv::rail_process_min_max_info:")); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_client_status(struct stream* s, int size) +rail_process_client_status(struct stream *s, int size) { - int flags; + int flags; - LOG(10, ("chansrv::rail_process_client_status:")); - in_uint32_le(s, flags); - LOG(10, (" flags 0x%8.8x", flags)); - return 0; + LOG(10, ("chansrv::rail_process_client_status:")); + in_uint32_le(s, flags); + LOG(10, (" flags 0x%8.8x", flags)); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_sys_menu(struct stream* s, int size) +rail_process_sys_menu(struct stream *s, int size) { - int window_id; - int left; - int top; + int window_id; + int left; + int top; - LOG(10, ("chansrv::rail_process_sys_menu:")); - in_uint32_le(s, window_id); - in_uint16_le(s, left); - in_uint16_le(s, top); - LOG(10, (" window_id 0x%8.8x left %d top %d", window_id, left, top)); - return 0; + LOG(10, ("chansrv::rail_process_sys_menu:")); + in_uint32_le(s, window_id); + in_uint16_le(s, left); + in_uint16_le(s, top); + LOG(10, (" window_id 0x%8.8x left %d top %d", window_id, left, top)); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_lang_bar_info(struct stream* s, int size) +rail_process_lang_bar_info(struct stream *s, int size) { - int language_bar_status; + int language_bar_status; - LOG(10, ("chansrv::rail_process_lang_bar_info:")); - in_uint32_le(s, language_bar_status); - LOG(10, (" language_bar_status 0x%8.8x", language_bar_status)); - return 0; + LOG(10, ("chansrv::rail_process_lang_bar_info:")); + in_uint32_le(s, language_bar_status); + LOG(10, (" language_bar_status 0x%8.8x", language_bar_status)); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_appid_req(struct stream* s, int size) +rail_process_appid_req(struct stream *s, int size) { - LOG(10, ("chansrv::rail_process_appid_req:")); - return 0; + LOG(10, ("chansrv::rail_process_appid_req:")); + return 0; } /*****************************************************************************/ static int APP_CC -rail_process_appid_resp(struct stream* s, int size) +rail_process_appid_resp(struct stream *s, int size) { - LOG(10, ("chansrv::rail_process_appid_resp:")); - return 0; + LOG(10, ("chansrv::rail_process_appid_resp:")); + return 0; } /*****************************************************************************/ /* server to client only */ static int APP_CC -rail_process_exec_result(struct stream* s, int size) +rail_process_exec_result(struct stream *s, int size) { - LOG(10, ("chansrv::rail_process_exec_result:")); - return 0; + LOG(10, ("chansrv::rail_process_exec_result:")); + return 0; } /*****************************************************************************/ /* data in from client ( client -> xrdp -> chansrv ) */ int APP_CC -rail_data_in(struct stream* s, int chan_id, int chan_flags, int length, +rail_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) { - int code; - int size; + int code; + int size; - LOG(10, ("chansrv::rail_data_in:")); - in_uint8(s, code); - in_uint8s(s, 1); - in_uint16_le(s, size); - switch (code) - { - case TS_RAIL_ORDER_EXEC: /* 1 */ - rail_process_exec(s, size); - break; - case TS_RAIL_ORDER_ACTIVATE: /* 2 */ - rail_process_activate(s, size); - break; - case TS_RAIL_ORDER_SYSPARAM: /* 3 */ - rail_process_system_param(s, size); - break; - case TS_RAIL_ORDER_SYSCOMMAND: /* 4 */ - rail_process_system_command(s, size); - break; - case TS_RAIL_ORDER_HANDSHAKE: /* 5 */ - rail_process_handshake(s, size); - break; - case TS_RAIL_ORDER_NOTIFY_EVENT: /* 6 */ - rail_process_notify_event(s, size); - break; - case TS_RAIL_ORDER_WINDOWMOVE: /* 8 */ - rail_process_window_move(s, size); - break; - case TS_RAIL_ORDER_LOCALMOVESIZE: /* 9 */ - rail_process_local_move_size(s, size); - break; - case TS_RAIL_ORDER_MINMAXINFO: /* 10 */ - rail_process_min_max_info(s, size); - break; - case TS_RAIL_ORDER_CLIENTSTATUS: /* 11 */ - rail_process_client_status(s, size); - break; - case TS_RAIL_ORDER_SYSMENU: /* 12 */ - rail_process_sys_menu(s, size); - break; - case TS_RAIL_ORDER_LANGBARINFO: /* 13 */ - rail_process_lang_bar_info(s, size); - break; - case TS_RAIL_ORDER_GET_APPID_REQ: /* 14 */ - rail_process_appid_req(s, size); - break; - case TS_RAIL_ORDER_GET_APPID_RESP: /* 15 */ - rail_process_appid_resp(s, size); - break; - case TS_RAIL_ORDER_EXEC_RESULT: /* 128 */ - rail_process_exec_result(s, size); - break; - default: - LOG(10, ("rail_data_in: unknown code %d size %d", code, size)); - break; - } - XFlush(g_display); - return 0; + LOG(10, ("chansrv::rail_data_in:")); + in_uint8(s, code); + in_uint8s(s, 1); + in_uint16_le(s, size); + + switch (code) + { + case TS_RAIL_ORDER_EXEC: /* 1 */ + rail_process_exec(s, size); + break; + case TS_RAIL_ORDER_ACTIVATE: /* 2 */ + rail_process_activate(s, size); + break; + case TS_RAIL_ORDER_SYSPARAM: /* 3 */ + rail_process_system_param(s, size); + break; + case TS_RAIL_ORDER_SYSCOMMAND: /* 4 */ + rail_process_system_command(s, size); + break; + case TS_RAIL_ORDER_HANDSHAKE: /* 5 */ + rail_process_handshake(s, size); + break; + case TS_RAIL_ORDER_NOTIFY_EVENT: /* 6 */ + rail_process_notify_event(s, size); + break; + case TS_RAIL_ORDER_WINDOWMOVE: /* 8 */ + rail_process_window_move(s, size); + break; + case TS_RAIL_ORDER_LOCALMOVESIZE: /* 9 */ + rail_process_local_move_size(s, size); + break; + case TS_RAIL_ORDER_MINMAXINFO: /* 10 */ + rail_process_min_max_info(s, size); + break; + case TS_RAIL_ORDER_CLIENTSTATUS: /* 11 */ + rail_process_client_status(s, size); + break; + case TS_RAIL_ORDER_SYSMENU: /* 12 */ + rail_process_sys_menu(s, size); + break; + case TS_RAIL_ORDER_LANGBARINFO: /* 13 */ + rail_process_lang_bar_info(s, size); + break; + case TS_RAIL_ORDER_GET_APPID_REQ: /* 14 */ + rail_process_appid_req(s, size); + break; + case TS_RAIL_ORDER_GET_APPID_RESP: /* 15 */ + rail_process_appid_resp(s, size); + break; + case TS_RAIL_ORDER_EXEC_RESULT: /* 128 */ + rail_process_exec_result(s, size); + break; + default: + LOG(10, ("rail_data_in: unknown code %d size %d", code, size)); + break; + } + + XFlush(g_display); + return 0; } /*****************************************************************************/ /* returns 0, event handled, 1 unhandled */ int APP_CC -rail_xevent(void* xevent) +rail_xevent(void *xevent) { - XEvent* lxevent; - XWindowChanges xwc; - int rv; - int nchildren_return = 0; - Window root_return; - Window parent_return; - Window *children_return; - Window wreturn; - int revert_to; - XWindowAttributes wnd_attributes; + XEvent *lxevent; + XWindowChanges xwc; + int rv; + int nchildren_return = 0; + Window root_return; + Window parent_return; + Window *children_return; + Window wreturn; + int revert_to; + XWindowAttributes wnd_attributes; - LOG(10, ("chansrv::rail_xevent:")); - if (!g_rail_up) - { - return 1; - } - rv = 1; - lxevent = (XEvent*)xevent; - switch (lxevent->type) - { - case ConfigureRequest: - LOG(10, (" got ConfigureRequest window_id 0x%8.8x", lxevent->xconfigurerequest.window)); - g_memset(&xwc, 0, sizeof(xwc)); - xwc.x = lxevent->xconfigurerequest.x; - xwc.y = lxevent->xconfigurerequest.y; - xwc.width = lxevent->xconfigurerequest.width; - xwc.height = lxevent->xconfigurerequest.height; - xwc.border_width = lxevent->xconfigurerequest.border_width; - xwc.sibling = lxevent->xconfigurerequest.above; - xwc.stack_mode = lxevent->xconfigurerequest.detail; - XConfigureWindow(g_display, - lxevent->xconfigurerequest.window, - lxevent->xconfigurerequest.value_mask, - &xwc); - rv = 0; - break; + LOG(10, ("chansrv::rail_xevent:")); - case MapRequest: - LOG(10, (" got MapRequest")); - XMapWindow(g_display, lxevent->xmaprequest.window); - rv = 0; - break; + if (!g_rail_up) + { + return 1; + } - case MapNotify: - LOG(10, (" got MapNotify")); - break; + rv = 1; + lxevent = (XEvent *)xevent; - case UnmapNotify: - LOG(10, (" got UnmapNotify")); - break; + switch (lxevent->type) + { + case ConfigureRequest: + LOG(10, (" got ConfigureRequest window_id 0x%8.8x", lxevent->xconfigurerequest.window)); + g_memset(&xwc, 0, sizeof(xwc)); + xwc.x = lxevent->xconfigurerequest.x; + xwc.y = lxevent->xconfigurerequest.y; + xwc.width = lxevent->xconfigurerequest.width; + xwc.height = lxevent->xconfigurerequest.height; + xwc.border_width = lxevent->xconfigurerequest.border_width; + xwc.sibling = lxevent->xconfigurerequest.above; + xwc.stack_mode = lxevent->xconfigurerequest.detail; + XConfigureWindow(g_display, + lxevent->xconfigurerequest.window, + lxevent->xconfigurerequest.value_mask, + &xwc); + rv = 0; + break; - case ConfigureNotify: - LOG(10, (" got ConfigureNotify")); - break; + case MapRequest: + LOG(10, (" got MapRequest")); + XMapWindow(g_display, lxevent->xmaprequest.window); + rv = 0; + break; - case FocusIn: - LOG(10, (" got FocusIn")); - break; + case MapNotify: + LOG(10, (" got MapNotify")); + break; - case ButtonPress: - LOG(10, (" got ButtonPress")); - break; + case UnmapNotify: + LOG(10, (" got UnmapNotify")); + break; - case EnterNotify: - LOG(10, (" got EnterNotify")); - break; + case ConfigureNotify: + LOG(10, (" got ConfigureNotify")); + break; - case LeaveNotify: - LOG(10, (" got LeaveNotify")); - break; + case FocusIn: + LOG(10, (" got FocusIn")); + break; - } - return rv; + case ButtonPress: + LOG(10, (" got ButtonPress")); + break; + + case EnterNotify: + LOG(10, (" got EnterNotify")); + break; + + case LeaveNotify: + LOG(10, (" got LeaveNotify")); + break; + + } + + return rv; } diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c index e4d54bb0..e8b801c6 100644 --- a/sesman/chansrv/sound.c +++ b/sesman/chansrv/sound.c @@ -28,100 +28,100 @@ static int g_training_sent_time = 0; static int g_cBlockNo = 0; #if defined(XRDP_SIMPLESOUND) -static void* DEFAULT_CC -read_raw_audio_data(void* arg); +static void *DEFAULT_CC +read_raw_audio_data(void *arg); #endif /*****************************************************************************/ static int APP_CC sound_send_server_formats(void) { - struct stream* s; - int bytes; - char* size_ptr; + struct stream *s; + int bytes; + char *size_ptr; - print_got_here(); + print_got_here(); - make_stream(s); - init_stream(s, 8182); - out_uint16_le(s, SNDC_FORMATS); - size_ptr = s->p; - out_uint16_le(s, 0); /* size, set later */ - out_uint32_le(s, 0); /* dwFlags */ - out_uint32_le(s, 0); /* dwVolume */ - out_uint32_le(s, 0); /* dwPitch */ - out_uint16_le(s, 0); /* wDGramPort */ - out_uint16_le(s, 1); /* wNumberOfFormats */ - out_uint8(s, g_cBlockNo); /* cLastBlockConfirmed */ - out_uint16_le(s, 2); /* wVersion */ - out_uint8(s, 0); /* bPad */ + make_stream(s); + init_stream(s, 8182); + out_uint16_le(s, SNDC_FORMATS); + size_ptr = s->p; + out_uint16_le(s, 0); /* size, set later */ + out_uint32_le(s, 0); /* dwFlags */ + out_uint32_le(s, 0); /* dwVolume */ + out_uint32_le(s, 0); /* dwPitch */ + out_uint16_le(s, 0); /* wDGramPort */ + out_uint16_le(s, 1); /* wNumberOfFormats */ + out_uint8(s, g_cBlockNo); /* cLastBlockConfirmed */ + out_uint16_le(s, 2); /* wVersion */ + out_uint8(s, 0); /* bPad */ - /* sndFormats */ - /* - wFormatTag 2 byte offset 0 - nChannels 2 byte offset 2 - nSamplesPerSec 4 byte offset 4 - nAvgBytesPerSec 4 byte offset 8 - nBlockAlign 2 byte offset 12 - wBitsPerSample 2 byte offset 14 - cbSize 2 byte offset 16 - data variable offset 18 - */ + /* sndFormats */ + /* + wFormatTag 2 byte offset 0 + nChannels 2 byte offset 2 + nSamplesPerSec 4 byte offset 4 + nAvgBytesPerSec 4 byte offset 8 + nBlockAlign 2 byte offset 12 + wBitsPerSample 2 byte offset 14 + cbSize 2 byte offset 16 + data variable offset 18 + */ - /* examples - 01 00 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 ....D........... - 00 00 - 01 00 02 00 22 56 00 00 88 58 01 00 04 00 10 00 ...."V...X...... - 00 00 - */ + /* examples + 01 00 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 ....D........... + 00 00 + 01 00 02 00 22 56 00 00 88 58 01 00 04 00 10 00 ...."V...X...... + 00 00 + */ - out_uint16_le(s, 1); // wFormatTag - WAVE_FORMAT_PCM - out_uint16_le(s, 2); // num of channels - out_uint32_le(s, 44100); // samples per sec - out_uint32_le(s, 176400); // avg bytes per sec - out_uint16_le(s, 4); // block align - out_uint16_le(s, 16); // bits per sample - out_uint16_le(s, 0); // size + out_uint16_le(s, 1); // wFormatTag - WAVE_FORMAT_PCM + out_uint16_le(s, 2); // num of channels + out_uint32_le(s, 44100); // samples per sec + out_uint32_le(s, 176400); // avg bytes per sec + out_uint16_le(s, 4); // block align + out_uint16_le(s, 16); // bits per sample + out_uint16_le(s, 0); // size - s_mark_end(s); - bytes = (int)((s->end - s->data) - 4); - size_ptr[0] = bytes; - size_ptr[1] = bytes >> 8; - bytes = (int)(s->end - s->data); - send_channel_data(g_rdpsnd_chan_id, s->data, bytes); - free_stream(s); - return 0; + s_mark_end(s); + bytes = (int)((s->end - s->data) - 4); + size_ptr[0] = bytes; + size_ptr[1] = bytes >> 8; + bytes = (int)(s->end - s->data); + send_channel_data(g_rdpsnd_chan_id, s->data, bytes); + free_stream(s); + return 0; } /*****************************************************************************/ static int sound_send_training(void) { - struct stream* s; - int bytes; - int time; - char* size_ptr; + struct stream *s; + int bytes; + int time; + char *size_ptr; - print_got_here(); + print_got_here(); - make_stream(s); - init_stream(s, 8182); - out_uint16_le(s, SNDC_TRAINING); - size_ptr = s->p; - out_uint16_le(s, 0); /* size, set later */ - time = g_time2(); - g_training_sent_time = time; - out_uint16_le(s, time); - out_uint16_le(s, 1024); - out_uint8s(s, (1024 - 4)); - s_mark_end(s); - bytes = (int)((s->end - s->data) - 4); - size_ptr[0] = bytes; - size_ptr[1] = bytes >> 8; - bytes = (int)(s->end - s->data); - send_channel_data(g_rdpsnd_chan_id, s->data, bytes); - free_stream(s); - return 0; + make_stream(s); + init_stream(s, 8182); + out_uint16_le(s, SNDC_TRAINING); + size_ptr = s->p; + out_uint16_le(s, 0); /* size, set later */ + time = g_time2(); + g_training_sent_time = time; + out_uint16_le(s, time); + out_uint16_le(s, 1024); + out_uint8s(s, (1024 - 4)); + s_mark_end(s); + bytes = (int)((s->end - s->data) - 4); + size_ptr[0] = bytes; + size_ptr[1] = bytes >> 8; + bytes = (int)(s->end - s->data); + send_channel_data(g_rdpsnd_chan_id, s->data, bytes); + free_stream(s); + return 0; } /*****************************************************************************/ @@ -132,318 +132,339 @@ sound_send_training(void) */ static int APP_CC -sound_process_formats(struct stream* s, int size) +sound_process_formats(struct stream *s, int size) { - int num_formats; + int num_formats; - print_got_here(); + print_got_here(); - LOG(0, ("sound_process_formats:")); - if (size < 16) - { - return 1; - } - in_uint8s(s, 14); - in_uint16_le(s, num_formats); - if (num_formats > 0) - { - sound_send_training(); - } - return 0; + LOG(0, ("sound_process_formats:")); + + if (size < 16) + { + return 1; + } + + in_uint8s(s, 14); + in_uint16_le(s, num_formats); + + if (num_formats > 0) + { + sound_send_training(); + } + + return 0; } /*****************************************************************************/ static int -sound_send_wave_data(char* data, int data_bytes) +sound_send_wave_data(char *data, int data_bytes) { - struct stream* s; - int bytes; - int time; - char* size_ptr; + struct stream *s; + int bytes; + int time; + char *size_ptr; - print_got_here(); + print_got_here(); - if ((data_bytes < 4) || (data_bytes > 32 * 1024)) - { - LOG(0, ("sound_send_wave_data: bad data_bytes %d", data_bytes)); - } + if ((data_bytes < 4) || (data_bytes > 32 * 1024)) + { + LOG(0, ("sound_send_wave_data: bad data_bytes %d", data_bytes)); + } - /* part one of 2 PDU wave info */ + /* part one of 2 PDU wave info */ - LOG(10, ("sound_send_wave_data: sending %d bytes", data_bytes)); + LOG(10, ("sound_send_wave_data: sending %d bytes", data_bytes)); - make_stream(s); - init_stream(s, data_bytes); - out_uint16_le(s, SNDC_WAVE); - size_ptr = s->p; - out_uint16_le(s, 0); /* size, set later */ - time = g_time2(); - out_uint16_le(s, time); - out_uint16_le(s, 0); /* wFormatNo */ - g_cBlockNo++; - out_uint8(s, g_cBlockNo); + make_stream(s); + init_stream(s, data_bytes); + out_uint16_le(s, SNDC_WAVE); + size_ptr = s->p; + out_uint16_le(s, 0); /* size, set later */ + time = g_time2(); + out_uint16_le(s, time); + out_uint16_le(s, 0); /* wFormatNo */ + g_cBlockNo++; + out_uint8(s, g_cBlockNo); - LOG(10, ("sound_send_wave_data: sending time %d, g_cBlockNo %d", - time & 0xffff, g_cBlockNo & 0xff)); + LOG(10, ("sound_send_wave_data: sending time %d, g_cBlockNo %d", + time & 0xffff, g_cBlockNo & 0xff)); - out_uint8s(s, 3); - out_uint8a(s, data, 4); - s_mark_end(s); - bytes = (int)((s->end - s->data) - 4); - bytes += data_bytes; - bytes -= 4; - size_ptr[0] = bytes; - size_ptr[1] = bytes >> 8; - bytes = (int)(s->end - s->data); - send_channel_data(g_rdpsnd_chan_id, s->data, bytes); + out_uint8s(s, 3); + out_uint8a(s, data, 4); + s_mark_end(s); + bytes = (int)((s->end - s->data) - 4); + bytes += data_bytes; + bytes -= 4; + size_ptr[0] = bytes; + size_ptr[1] = bytes >> 8; + bytes = (int)(s->end - s->data); + send_channel_data(g_rdpsnd_chan_id, s->data, bytes); - /* part two of 2 PDU wave info */ - init_stream(s, data_bytes); - out_uint32_le(s, 0); - out_uint8a(s, data + 4, data_bytes - 4); - s_mark_end(s); - bytes = (int)(s->end - s->data); - send_channel_data(g_rdpsnd_chan_id, s->data, bytes); - free_stream(s); - return 0; + /* part two of 2 PDU wave info */ + init_stream(s, data_bytes); + out_uint32_le(s, 0); + out_uint8a(s, data + 4, data_bytes - 4); + s_mark_end(s); + bytes = (int)(s->end - s->data); + send_channel_data(g_rdpsnd_chan_id, s->data, bytes); + free_stream(s); + return 0; } /*****************************************************************************/ static int APP_CC -sound_process_training(struct stream* s, int size) +sound_process_training(struct stream *s, int size) { - int time_diff; + int time_diff; - print_got_here(); + print_got_here(); - time_diff = g_time2() - g_training_sent_time; - LOG(0, ("sound_process_training: round trip time %u", time_diff)); - return 0; + time_diff = g_time2() - g_training_sent_time; + LOG(0, ("sound_process_training: round trip time %u", time_diff)); + return 0; } /*****************************************************************************/ static int APP_CC -sound_process_wave_confirm(struct stream* s, int size) +sound_process_wave_confirm(struct stream *s, int size) { - int wTimeStamp; - int cConfirmedBlockNo; + int wTimeStamp; + int cConfirmedBlockNo; - print_got_here(); + print_got_here(); - in_uint16_le(s, wTimeStamp); - in_uint8(s, cConfirmedBlockNo); + in_uint16_le(s, wTimeStamp); + in_uint8(s, cConfirmedBlockNo); - LOG(10, ("sound_process_wave_confirm: wTimeStamp %d, cConfirmedBlockNo %d", - wTimeStamp, cConfirmedBlockNo)); + LOG(10, ("sound_process_wave_confirm: wTimeStamp %d, cConfirmedBlockNo %d", + wTimeStamp, cConfirmedBlockNo)); - return 0; + return 0; } /*****************************************************************************/ static int APP_CC -process_pcm_message(int id, int size, struct stream* s) +process_pcm_message(int id, int size, struct stream *s) { - print_got_here(); + print_got_here(); - sound_send_wave_data(s->p, size); - return 0; + sound_send_wave_data(s->p, size); + return 0; } /*****************************************************************************/ /* data coming in from audio source, eg pulse, alsa */ static int DEFAULT_CC -sound_trans_audio_data_in(struct trans* trans) +sound_trans_audio_data_in(struct trans *trans) { - struct stream *s; - int id; - int size; - int error; + struct stream *s; + int id; + int size; + int error; - if (trans == 0) - { - return 0; - } - if (trans != g_audio_c_trans) - { - return 1; - } - s = trans_get_in_s(trans); - in_uint32_le(s, id); - in_uint32_le(s, size); - if ((id != 0) || (size > 32 * 1024 + 8) || (size < 1)) - { - LOG(0, ("sound_trans_audio_data_in: bad message id %d size %d", id, size)); - return 1; - } - error = trans_force_read(trans, size - 8); - if (error == 0) - { - /* here, the entire message block is read in, process it */ - error = process_pcm_message(id, size - 8, s); - } - return error; + if (trans == 0) + { + return 0; + } + + if (trans != g_audio_c_trans) + { + return 1; + } + + s = trans_get_in_s(trans); + in_uint32_le(s, id); + in_uint32_le(s, size); + + if ((id != 0) || (size > 32 * 1024 + 8) || (size < 1)) + { + LOG(0, ("sound_trans_audio_data_in: bad message id %d size %d", id, size)); + return 1; + } + + error = trans_force_read(trans, size - 8); + + if (error == 0) + { + /* here, the entire message block is read in, process it */ + error = process_pcm_message(id, size - 8, s); + } + + return error; } /*****************************************************************************/ static int DEFAULT_CC sound_trans_audio_conn_in(struct trans *trans, struct trans *new_trans) { - print_got_here(); + print_got_here(); - if (trans == 0) - { - return 1; - } - if (trans != g_audio_l_trans) - { - return 1; - } - if (g_audio_c_trans != 0) /* if already set, error */ - { - return 1; - } - if (new_trans == 0) - { - return 1; - } - g_audio_c_trans = new_trans; - g_audio_c_trans->trans_data_in = sound_trans_audio_data_in; - g_audio_c_trans->header_size = 8; - trans_delete(g_audio_l_trans); - g_audio_l_trans = 0; - return 0; + if (trans == 0) + { + return 1; + } + + if (trans != g_audio_l_trans) + { + return 1; + } + + if (g_audio_c_trans != 0) /* if already set, error */ + { + return 1; + } + + if (new_trans == 0) + { + return 1; + } + + g_audio_c_trans = new_trans; + g_audio_c_trans->trans_data_in = sound_trans_audio_data_in; + g_audio_c_trans->header_size = 8; + trans_delete(g_audio_l_trans); + g_audio_l_trans = 0; + return 0; } /*****************************************************************************/ int APP_CC sound_init(void) { - char port[256]; - int error; + char port[256]; + int error; - print_got_here(); - LOG(0, ("sound_init:")); + print_got_here(); + LOG(0, ("sound_init:")); - sound_send_server_formats(); - g_audio_l_trans = trans_create(2, 33 * 1024, 8192); - g_snprintf(port, 255, "/tmp/xrdp_chansrv_audio_socket_%d", g_display_num); - g_audio_l_trans->trans_conn_in = sound_trans_audio_conn_in; - error = trans_listen(g_audio_l_trans, port); - if (error != 0) - { - LOG(0, ("sound_init: trans_listen failed")); - } + sound_send_server_formats(); + g_audio_l_trans = trans_create(2, 33 * 1024, 8192); + g_snprintf(port, 255, "/tmp/xrdp_chansrv_audio_socket_%d", g_display_num); + g_audio_l_trans->trans_conn_in = sound_trans_audio_conn_in; + error = trans_listen(g_audio_l_trans, port); + + if (error != 0) + { + LOG(0, ("sound_init: trans_listen failed")); + } #if defined(XRDP_SIMPLESOUND) - /* start thread to read raw audio data from pulseaudio device */ - tc_thread_create(read_raw_audio_data, 0); + /* start thread to read raw audio data from pulseaudio device */ + tc_thread_create(read_raw_audio_data, 0); #endif - return 0; + return 0; } /*****************************************************************************/ int APP_CC sound_deinit(void) { - print_got_here(); + print_got_here(); - if (g_audio_l_trans != 0) - { - trans_delete(g_audio_l_trans); - g_audio_l_trans = 0; - } - if (g_audio_c_trans != 0) - { - trans_delete(g_audio_c_trans); - g_audio_l_trans = 0; - } + if (g_audio_l_trans != 0) + { + trans_delete(g_audio_l_trans); + g_audio_l_trans = 0; + } - return 0; + if (g_audio_c_trans != 0) + { + trans_delete(g_audio_c_trans); + g_audio_l_trans = 0; + } + + return 0; } /*****************************************************************************/ /* data in from client ( clinet -> xrdp -> chansrv ) */ int APP_CC -sound_data_in(struct stream* s, int chan_id, int chan_flags, int length, +sound_data_in(struct stream *s, int chan_id, int chan_flags, int length, int total_length) { - int code; - int size; + int code; + int size; - print_got_here(); + print_got_here(); - in_uint8(s, code); - in_uint8s(s, 1); - in_uint16_le(s, size); - switch (code) - { - case SNDC_WAVECONFIRM: - sound_process_wave_confirm(s, size); - break; + in_uint8(s, code); + in_uint8s(s, 1); + in_uint16_le(s, size); - case SNDC_TRAINING: - sound_process_training(s, size); - break; + switch (code) + { + case SNDC_WAVECONFIRM: + sound_process_wave_confirm(s, size); + break; - case SNDC_FORMATS: - sound_process_formats(s, size); - break; + case SNDC_TRAINING: + sound_process_training(s, size); + break; - default: - LOG(0, ("sound_data_in: unknown code %d size %d", code, size)); - break; - } - return 0; + case SNDC_FORMATS: + sound_process_formats(s, size); + break; + + default: + LOG(0, ("sound_data_in: unknown code %d size %d", code, size)); + break; + } + + return 0; } /*****************************************************************************/ int APP_CC -sound_get_wait_objs(tbus* objs, int* count, int* timeout) +sound_get_wait_objs(tbus *objs, int *count, int *timeout) { - int lcount; + int lcount; - lcount = *count; - if (g_audio_l_trans != 0) - { - objs[lcount] = g_audio_l_trans->sck; - lcount++; - } - if (g_audio_c_trans != 0) - { - objs[lcount] = g_audio_c_trans->sck; - lcount++; - } - *count = lcount; - return 0; + lcount = *count; + + if (g_audio_l_trans != 0) + { + objs[lcount] = g_audio_l_trans->sck; + lcount++; + } + + if (g_audio_c_trans != 0) + { + objs[lcount] = g_audio_c_trans->sck; + lcount++; + } + + *count = lcount; + return 0; } /*****************************************************************************/ int APP_CC sound_check_wait_objs(void) { - if (g_audio_l_trans != 0) - { - trans_check_wait_objs(g_audio_l_trans); - } + if (g_audio_l_trans != 0) + { + trans_check_wait_objs(g_audio_l_trans); + } - if (g_audio_c_trans != 0) - { - trans_check_wait_objs(g_audio_c_trans); - } + if (g_audio_c_trans != 0) + { + trans_check_wait_objs(g_audio_c_trans); + } - return 0; + return 0; } #if defined(XRDP_SIMPLESOUND) static int DEFAULT_CC -sttrans_data_in(struct trans* self) +sttrans_data_in(struct trans *self) { - LOG(0, ("sttrans_data_in:\n")); - return 0; + LOG(0, ("sttrans_data_in:\n")); + return 0; } /** @@ -451,103 +472,112 @@ sttrans_data_in(struct trans* self) * to a unix domain socket on which trans server is listening */ -static void* DEFAULT_CC -read_raw_audio_data(void* arg) +static void *DEFAULT_CC +read_raw_audio_data(void *arg) { - pa_sample_spec samp_spec; - pa_simple* simple = NULL; - uint32_t bytes_read; - char* cptr; - int i; - int error; - struct trans* strans; - char path[256]; - struct stream* outs; + pa_sample_spec samp_spec; + pa_simple *simple = NULL; + uint32_t bytes_read; + char *cptr; + int i; + int error; + struct trans *strans; + char path[256]; + struct stream *outs; - strans = trans_create(TRANS_MODE_UNIX, 8192, 8192); - if (strans == 0) - { - LOG(0, ("read_raw_audio_data: trans_create failed\n")); - return 0; - } - strans->trans_data_in = sttrans_data_in; - g_snprintf(path, 255, "/tmp/xrdp_chansrv_audio_socket_%d", g_display_num); - if (trans_connect(strans, "", path, 100) != 0) - { - LOG(0, ("read_raw_audio_data: trans_connect failed\n")); - trans_delete(strans); - return 0; - } + strans = trans_create(TRANS_MODE_UNIX, 8192, 8192); - /* setup audio format */ - samp_spec.format = PA_SAMPLE_S16LE; - samp_spec.rate = 44100; - samp_spec.channels = 2; - - /* if we are root, then for first 8 seconds connection to pulseaudo server - fails; if we are non-root, then connection succeeds on first attempt; - for now we have changed code to be non-root, but this may change in the - future - so pretend we are root and try connecting to pulseaudio server - for upto one minute */ - for (i = 0; i < 60; i++) - { - simple = pa_simple_new(NULL, "xrdp", PA_STREAM_RECORD, NULL, - "record", &samp_spec, NULL, NULL, &error); - if (simple) + if (strans == 0) { - /* connected to pulseaudio server */ - LOG(0, ("read_raw_audio_data: connected to pulseaudio server\n")); - break; + LOG(0, ("read_raw_audio_data: trans_create failed\n")); + return 0; } - LOG(0, ("read_raw_audio_data: ERROR creating PulseAudio async interface\n")); - LOG(0, ("read_raw_audio_data: %s\n", pa_strerror(error))); - g_sleep(1000); - } - if (i == 60) - { - /* failed to connect to audio server */ + strans->trans_data_in = sttrans_data_in; + g_snprintf(path, 255, "/tmp/xrdp_chansrv_audio_socket_%d", g_display_num); + + if (trans_connect(strans, "", path, 100) != 0) + { + LOG(0, ("read_raw_audio_data: trans_connect failed\n")); + trans_delete(strans); + return 0; + } + + /* setup audio format */ + samp_spec.format = PA_SAMPLE_S16LE; + samp_spec.rate = 44100; + samp_spec.channels = 2; + + /* if we are root, then for first 8 seconds connection to pulseaudo server + fails; if we are non-root, then connection succeeds on first attempt; + for now we have changed code to be non-root, but this may change in the + future - so pretend we are root and try connecting to pulseaudio server + for upto one minute */ + for (i = 0; i < 60; i++) + { + simple = pa_simple_new(NULL, "xrdp", PA_STREAM_RECORD, NULL, + "record", &samp_spec, NULL, NULL, &error); + + if (simple) + { + /* connected to pulseaudio server */ + LOG(0, ("read_raw_audio_data: connected to pulseaudio server\n")); + break; + } + + LOG(0, ("read_raw_audio_data: ERROR creating PulseAudio async interface\n")); + LOG(0, ("read_raw_audio_data: %s\n", pa_strerror(error))); + g_sleep(1000); + } + + if (i == 60) + { + /* failed to connect to audio server */ + trans_delete(strans); + return NULL; + } + + /* insert header just once */ + outs = trans_get_out_s(strans, 8192); + out_uint32_le(outs, 0); + out_uint32_le(outs, AUDIO_BUF_SIZE + 8); + cptr = outs->p; + out_uint8s(outs, AUDIO_BUF_SIZE); + s_mark_end(outs); + + while (1) + { + /* read a block of raw audio data... */ + g_memset(cptr, 0, 4); + bytes_read = pa_simple_read(simple, cptr, AUDIO_BUF_SIZE, &error); + + if (bytes_read < 0) + { + LOG(0, ("read_raw_audio_data: ERROR reading from pulseaudio stream\n")); + LOG(0, ("read_raw_audio_data: %s\n", pa_strerror(error))); + break; + } + + /* bug workaround: + even when there is no audio data, pulseaudio is returning without + errors but the data itself is zero; we use this zero data to + determine that there is no audio data present */ + if (*cptr == 0 && *(cptr + 1) == 0 && *(cptr + 2) == 0 && *(cptr + 3) == 0) + { + g_sleep(10); + continue; + } + + if (trans_force_write_s(strans, outs) != 0) + { + LOG(0, ("read_raw_audio_data: ERROR writing audio data to server\n")); + break; + } + } + + pa_simple_free(simple); trans_delete(strans); return NULL; - } - - /* insert header just once */ - outs = trans_get_out_s(strans, 8192); - out_uint32_le(outs, 0); - out_uint32_le(outs, AUDIO_BUF_SIZE + 8); - cptr = outs->p; - out_uint8s(outs, AUDIO_BUF_SIZE); - s_mark_end(outs); - - while (1) - { - /* read a block of raw audio data... */ - g_memset(cptr, 0, 4); - bytes_read = pa_simple_read(simple, cptr, AUDIO_BUF_SIZE, &error); - if (bytes_read < 0) - { - LOG(0, ("read_raw_audio_data: ERROR reading from pulseaudio stream\n")); - LOG(0, ("read_raw_audio_data: %s\n", pa_strerror(error))); - break; - } - /* bug workaround: - even when there is no audio data, pulseaudio is returning without - errors but the data itself is zero; we use this zero data to - determine that there is no audio data present */ - if (*cptr == 0 && *(cptr + 1) == 0 && *(cptr + 2) == 0 && *(cptr + 3) == 0) - { - g_sleep(10); - continue; - } - if (trans_force_write_s(strans, outs) != 0) - { - LOG(0, ("read_raw_audio_data: ERROR writing audio data to server\n")); - break; - } - } - pa_simple_free(simple); - trans_delete(strans); - return NULL; } #endif diff --git a/sesman/chansrv/xcommon.c b/sesman/chansrv/xcommon.c index 70b52694..f7f95768 100644 --- a/sesman/chansrv/xcommon.c +++ b/sesman/chansrv/xcommon.c @@ -31,10 +31,10 @@ extern int g_waiting_for_data_response_time; /* in clipboard.c */ extern int g_rail_up; /* in rail.c */ -Display* g_display = 0; +Display *g_display = 0; int g_x_socket = 0; tbus g_x_wait_obj = 0; -Screen* g_screen = 0; +Screen *g_screen = 0; int g_screen_num = 0; Window g_root_window = 0; Atom g_wm_delete_window_atom = 0; @@ -42,15 +42,15 @@ Atom g_wm_protocols_atom = 0; /*****************************************************************************/ static int DEFAULT_CC -xcommon_error_handler(Display* dis, XErrorEvent* xer) +xcommon_error_handler(Display *dis, XErrorEvent *xer) { - char text[256]; + char text[256]; - XGetErrorText(dis, xer->error_code, text, 255); - LOGM((LOG_LEVEL_ERROR, "X error [%s](%d) opcodes %d/%d " - "resource 0x%lx", text, xer->error_code, - xer->request_code, xer->minor_code, xer->resourceid)); - return 0; + XGetErrorText(dis, xer->error_code, text, 255); + LOGM((LOG_LEVEL_ERROR, "X error [%s](%d) opcodes %d/%d " + "resource 0x%lx", text, xer->error_code, + xer->request_code, xer->minor_code, xer->resourceid)); + return 0; } /*****************************************************************************/ @@ -58,9 +58,9 @@ xcommon_error_handler(Display* dis, XErrorEvent* xer) Do any cleanup that needs to be done on exit, like removing temporary files. Don't worry about memory leaks */ static int DEFAULT_CC -xcommon_fatal_handler(Display* dis) +xcommon_fatal_handler(Display *dis) { - return 0; + return 0; } /*****************************************************************************/ @@ -71,7 +71,7 @@ xcommon_fatal_handler(Display* dis) int APP_CC xcommon_get_local_time(void) { - return g_time3(); + return g_time3(); } /******************************************************************************/ @@ -79,42 +79,45 @@ xcommon_get_local_time(void) int APP_CC xcommon_init(void) { - if (g_display != 0) - { - LOG(10, ("xcommon_init: xcommon_init already called")); + if (g_display != 0) + { + LOG(10, ("xcommon_init: xcommon_init already called")); + return 0; + } + + g_display = XOpenDisplay(0); + + if (g_display == 0) + { + LOGM((LOG_LEVEL_ERROR, "xcommon_init: error, XOpenDisplay failed")); + return 1; + } + + LOG(0, ("xcommon_init: connected to display ok")); + + /* setting the error handlers can cause problem when shutting down + chansrv on some xlibs */ + XSetErrorHandler(xcommon_error_handler); + //XSetIOErrorHandler(xcommon_fatal_handler); + + g_x_socket = XConnectionNumber(g_display); + + if (g_x_socket == 0) + { + LOGM((LOG_LEVEL_ERROR, "xcommon_init: XConnectionNumber failed")); + return 1; + } + + g_x_wait_obj = g_create_wait_obj_from_socket(g_x_socket, 0); + g_screen_num = DefaultScreen(g_display); + g_screen = ScreenOfDisplay(g_display, g_screen_num); + + g_root_window = RootWindowOfScreen(g_screen); + + g_wm_delete_window_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", 0); + g_wm_protocols_atom = XInternAtom(g_display, "WM_PROTOCOLS", 0); + return 0; - } - g_display = XOpenDisplay(0); - if (g_display == 0) - { - LOGM((LOG_LEVEL_ERROR, "xcommon_init: error, XOpenDisplay failed")); - return 1; - } - - LOG(0, ("xcommon_init: connected to display ok")); - - /* setting the error handlers can cause problem when shutting down - chansrv on some xlibs */ - XSetErrorHandler(xcommon_error_handler); - //XSetIOErrorHandler(xcommon_fatal_handler); - - g_x_socket = XConnectionNumber(g_display); - if (g_x_socket == 0) - { - LOGM((LOG_LEVEL_ERROR, "xcommon_init: XConnectionNumber failed")); - return 1; - } - - g_x_wait_obj = g_create_wait_obj_from_socket(g_x_socket, 0); - g_screen_num = DefaultScreen(g_display); - g_screen = ScreenOfDisplay(g_display, g_screen_num); - - g_root_window = RootWindowOfScreen(g_screen); - - g_wm_delete_window_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", 0); - g_wm_protocols_atom = XInternAtom(g_display, "WM_PROTOCOLS", 0); - - return 0; } /*****************************************************************************/ @@ -122,66 +125,73 @@ xcommon_init(void) this is called to get any wait objects for the main loop timeout can be nil */ int APP_CC -xcommon_get_wait_objs(tbus* objs, int* count, int* timeout) +xcommon_get_wait_objs(tbus *objs, int *count, int *timeout) { - int lcount; + int lcount; - if (((!g_clip_up) && (!g_rail_up)) || (objs == 0) || (count == 0)) - { - LOG(10, ("xcommon_get_wait_objs: nothing to do")); + if (((!g_clip_up) && (!g_rail_up)) || (objs == 0) || (count == 0)) + { + LOG(10, ("xcommon_get_wait_objs: nothing to do")); + return 0; + } + + lcount = *count; + objs[lcount] = g_x_wait_obj; + lcount++; + *count = lcount; return 0; - } - lcount = *count; - objs[lcount] = g_x_wait_obj; - lcount++; - *count = lcount; - return 0; } /*****************************************************************************/ int APP_CC xcommon_check_wait_objs(void) { - XEvent xevent; - int time_diff; - int clip_rv; - int rail_rv; + XEvent xevent; + int time_diff; + int clip_rv; + int rail_rv; + + if ((!g_clip_up) && (!g_rail_up)) + { + LOG(10, ("xcommon_check_wait_objs: nothing to do")); + return 0; + } + + if (g_is_wait_obj_set(g_x_wait_obj)) + { + if (XPending(g_display) < 1) + { + /* something is wrong, should not get here */ + LOGM((LOG_LEVEL_ERROR, "xcommon_check_wait_objs: sck closed")); + return 0; + } + + if (g_waiting_for_data_response) + { + time_diff = xcommon_get_local_time() - + g_waiting_for_data_response_time; + + if (time_diff > 10000) + { + LOGM((LOG_LEVEL_ERROR, "xcommon_check_wait_objs: warning, " + "waiting for data response too long")); + } + } + + while (XPending(g_display) > 0) + { + g_memset(&xevent, 0, sizeof(xevent)); + XNextEvent(g_display, &xevent); + + clip_rv = clipboard_xevent(&xevent); + rail_rv = rail_xevent(&xevent); + + if ((clip_rv == 1) && (rail_rv == 1)) + { + LOG(10, ("xcommon_check_wait_objs unknown xevent type %d", xevent.type)); + } + } + } - if ((!g_clip_up) && (!g_rail_up)) - { - LOG(10, ("xcommon_check_wait_objs: nothing to do")); return 0; - } - if (g_is_wait_obj_set(g_x_wait_obj)) - { - if (XPending(g_display) < 1) - { - /* something is wrong, should not get here */ - LOGM((LOG_LEVEL_ERROR, "xcommon_check_wait_objs: sck closed")); - return 0; - } - if (g_waiting_for_data_response) - { - time_diff = xcommon_get_local_time() - - g_waiting_for_data_response_time; - if (time_diff > 10000) - { - LOGM((LOG_LEVEL_ERROR, "xcommon_check_wait_objs: warning, " - "waiting for data response too long")); - } - } - while (XPending(g_display) > 0) - { - g_memset(&xevent, 0, sizeof(xevent)); - XNextEvent(g_display, &xevent); - - clip_rv = clipboard_xevent(&xevent); - rail_rv = rail_xevent(&xevent); - if ((clip_rv == 1) && (rail_rv == 1)) - { - LOG(10, ("xcommon_check_wait_objs unknown xevent type %d", xevent.type)); - } - } - } - return 0; } diff --git a/sesman/config.c b/sesman/config.c index a4342676..9938249f 100644 --- a/sesman/config.c +++ b/sesman/config.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -31,146 +30,153 @@ #include "sesman.h" #include "log.h" -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ /******************************************************************************/ int DEFAULT_CC -config_read(struct config_sesman* cfg) +config_read(struct config_sesman *cfg) { - int fd; - struct list* sec; - struct list* param_n; - struct list* param_v; - char cfg_file[256]; + int fd; + struct list *sec; + struct list *param_n; + struct list *param_v; + char cfg_file[256]; - g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); - fd = g_file_open(cfg_file); - if (-1 == fd) - { - //if (g_cfg->log.fd >= 0) - //{ - /* logging is already active */ - log_message(LOG_LEVEL_ALWAYS, "error opening %s in \ + g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); + fd = g_file_open(cfg_file); + + if (-1 == fd) + { + //if (g_cfg->log.fd >= 0) + //{ + /* logging is already active */ + log_message(LOG_LEVEL_ALWAYS, "error opening %s in \ config_read", cfg_file); - //} - //else - //{ - g_printf("error opening %s in config_read", cfg_file); - //} - return 1; - } - g_memset(cfg, 0, sizeof(struct config_sesman)); - sec = list_create(); - sec->auto_free = 1; - file_read_sections(fd, sec); - param_n = list_create(); - param_n->auto_free = 1; - param_v = list_create(); - param_v->auto_free = 1; + //} + //else + //{ + g_printf("error opening %s in config_read", cfg_file); + //} + return 1; + } - /* read global config */ - config_read_globals(fd, cfg, param_n, param_v); + g_memset(cfg, 0, sizeof(struct config_sesman)); + sec = list_create(); + sec->auto_free = 1; + file_read_sections(fd, sec); + param_n = list_create(); + param_n->auto_free = 1; + param_v = list_create(); + param_v->auto_free = 1; - /* read Xvnc/X11rdp parameter list */ - config_read_vnc_params(fd, cfg, param_n, param_v); - config_read_rdp_params(fd, cfg, param_n, param_v); + /* read global config */ + config_read_globals(fd, cfg, param_n, param_v); - /* read logging config */ - // config_read_logging(fd, &(cfg->log), param_n, param_v); + /* read Xvnc/X11rdp parameter list */ + config_read_vnc_params(fd, cfg, param_n, param_v); + config_read_rdp_params(fd, cfg, param_n, param_v); - /* read security config */ - config_read_security(fd, &(cfg->sec), param_n, param_v); + /* read logging config */ + // config_read_logging(fd, &(cfg->log), param_n, param_v); - /* read session config */ - config_read_sessions(fd, &(cfg->sess), param_n, param_v); + /* read security config */ + config_read_security(fd, &(cfg->sec), param_n, param_v); - /* cleanup */ - list_delete(sec); - list_delete(param_v); - list_delete(param_n); - g_file_close(fd); - return 0; + /* read session config */ + config_read_sessions(fd, &(cfg->sess), param_n, param_v); + + /* cleanup */ + list_delete(sec); + list_delete(param_v); + list_delete(param_n); + g_file_close(fd); + return 0; } /******************************************************************************/ int DEFAULT_CC -config_read_globals(int file, struct config_sesman* cf, struct list* param_n, - struct list* param_v) +config_read_globals(int file, struct config_sesman *cf, struct list *param_n, + struct list *param_v) { - int i; - char* buf; + int i; + char *buf; - list_clear(param_v); - list_clear(param_n); + list_clear(param_v); + list_clear(param_n); - /* resetting the struct */ - cf->listen_address[0] = '\0'; - cf->listen_port[0] = '\0'; - cf->enable_user_wm = 0; - cf->user_wm[0] = '\0'; - cf->default_wm[0] = '\0'; - cf->auth_file_path = 0; - - file_read_section(file, SESMAN_CFG_GLOBALS, param_n, param_v); - for (i = 0; i < param_n->count; i++) - { - buf = (char*)list_get_item(param_n, i); - if (0 == g_strcasecmp(buf, SESMAN_CFG_DEFWM)) - { - g_strncpy(cf->default_wm, (char*)list_get_item(param_v, i), 31); - } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_USERWM)) - { - g_strncpy(cf->user_wm, (char*)list_get_item(param_v, i), 31); - } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_ENABLE_USERWM)) - { - cf->enable_user_wm = text2bool((char*)list_get_item(param_v, i)); - } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_PORT)) - { - g_strncpy(cf->listen_port, (char*)list_get_item(param_v, i), 15); - } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_ADDRESS)) - { - g_strncpy(cf->listen_address, (char*)list_get_item(param_v, i), 31); - } - else if (0 == g_strcasecmp(buf, SESMAN_CFG_AUTH_FILE_PATH)) - { - cf->auth_file_path = g_strdup((char*)list_get_item(param_v, i)); - } - } - - /* checking for missing required parameters */ - if ('\0' == cf->listen_address[0]) - { - g_strncpy(cf->listen_address, "0.0.0.0", 8); - } - if ('\0' == cf->listen_port[0]) - { - g_strncpy(cf->listen_port, "3350", 5); - } - if ('\0' == cf->user_wm[0]) - { + /* resetting the struct */ + cf->listen_address[0] = '\0'; + cf->listen_port[0] = '\0'; cf->enable_user_wm = 0; - } - if ('\0' == cf->default_wm[0]) - { - g_strncpy(cf->default_wm, "startwm.sh", 11); - } + cf->user_wm[0] = '\0'; + cf->default_wm[0] = '\0'; + cf->auth_file_path = 0; - /* showing read config */ - g_printf("sesman config:\r\n"); - g_printf("\tListenAddress: %s\r\n", cf->listen_address); - g_printf("\tListenPort: %s\r\n", cf->listen_port); - g_printf("\tEnableUserWindowManager: %i\r\n", cf->enable_user_wm); - g_printf("\tUserWindowManager: %s\r\n", cf->user_wm); - g_printf("\tDefaultWindowManager: %s\r\n", cf->default_wm); - g_printf("\tAuthFilePath: %s\r\n", ((cf->auth_file_path) ? (cf->auth_file_path) : ("disabled"))); + file_read_section(file, SESMAN_CFG_GLOBALS, param_n, param_v); - return 0; + for (i = 0; i < param_n->count; i++) + { + buf = (char *)list_get_item(param_n, i); + + if (0 == g_strcasecmp(buf, SESMAN_CFG_DEFWM)) + { + g_strncpy(cf->default_wm, (char *)list_get_item(param_v, i), 31); + } + else if (0 == g_strcasecmp(buf, SESMAN_CFG_USERWM)) + { + g_strncpy(cf->user_wm, (char *)list_get_item(param_v, i), 31); + } + else if (0 == g_strcasecmp(buf, SESMAN_CFG_ENABLE_USERWM)) + { + cf->enable_user_wm = text2bool((char *)list_get_item(param_v, i)); + } + else if (0 == g_strcasecmp(buf, SESMAN_CFG_PORT)) + { + g_strncpy(cf->listen_port, (char *)list_get_item(param_v, i), 15); + } + else if (0 == g_strcasecmp(buf, SESMAN_CFG_ADDRESS)) + { + g_strncpy(cf->listen_address, (char *)list_get_item(param_v, i), 31); + } + else if (0 == g_strcasecmp(buf, SESMAN_CFG_AUTH_FILE_PATH)) + { + cf->auth_file_path = g_strdup((char *)list_get_item(param_v, i)); + } + } + + /* checking for missing required parameters */ + if ('\0' == cf->listen_address[0]) + { + g_strncpy(cf->listen_address, "0.0.0.0", 8); + } + + if ('\0' == cf->listen_port[0]) + { + g_strncpy(cf->listen_port, "3350", 5); + } + + if ('\0' == cf->user_wm[0]) + { + cf->enable_user_wm = 0; + } + + if ('\0' == cf->default_wm[0]) + { + g_strncpy(cf->default_wm, "startwm.sh", 11); + } + + /* showing read config */ + g_printf("sesman config:\r\n"); + g_printf("\tListenAddress: %s\r\n", cf->listen_address); + g_printf("\tListenPort: %s\r\n", cf->listen_port); + g_printf("\tEnableUserWindowManager: %i\r\n", cf->enable_user_wm); + g_printf("\tUserWindowManager: %s\r\n", cf->user_wm); + g_printf("\tDefaultWindowManager: %s\r\n", cf->default_wm); + g_printf("\tAuthFilePath: %s\r\n", ((cf->auth_file_path) ? (cf->auth_file_path) : ("disabled"))); + + return 0; } /****************************************************************************** @@ -184,7 +190,7 @@ config_read_logging(int file, struct log_config* lc, struct list* param_n, list_clear(param_v); list_clear(param_n); - // setting defaults + // setting defaults lc->program_name = g_strdup("sesman"); lc->log_file = 0; lc->fd = 0; @@ -230,185 +236,201 @@ config_read_logging(int file, struct log_config* lc, struct list* param_n, */ /******************************************************************************/ int DEFAULT_CC -config_read_security(int file, struct config_security* sc, - struct list* param_n, - struct list* param_v) +config_read_security(int file, struct config_security *sc, + struct list *param_n, + struct list *param_v) { - int i; - int gid; - char* buf; + int i; + int gid; + char *buf; - list_clear(param_v); - list_clear(param_n); + list_clear(param_v); + list_clear(param_n); - /* setting defaults */ - sc->allow_root = 0; - sc->login_retry = 3; - sc->ts_users_enable = 0; - sc->ts_admins_enable = 0; + /* setting defaults */ + sc->allow_root = 0; + sc->login_retry = 3; + sc->ts_users_enable = 0; + sc->ts_admins_enable = 0; - file_read_section(file, SESMAN_CFG_SECURITY, param_n, param_v); - for (i = 0; i < param_n->count; i++) - { - buf = (char*)list_get_item(param_n, i); - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALLOW_ROOT)) + file_read_section(file, SESMAN_CFG_SECURITY, param_n, param_v); + + for (i = 0; i < param_n->count; i++) { - sc->allow_root = text2bool((char*)list_get_item(param_v, i)); - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_LOGIN_RETRY)) - { - sc->login_retry = g_atoi((char*)list_get_item(param_v, i)); - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_USR_GROUP)) - { - if (g_getgroup_info((char*)list_get_item(param_v, i), &gid) == 0) - { - sc->ts_users_enable = 1; - sc->ts_users = gid; - } - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ADM_GROUP)) - { - if (g_getgroup_info((char*)list_get_item(param_v, i), &gid) == 0) - { - sc->ts_admins_enable = 1; - sc->ts_admins = gid; - } - } - } + buf = (char *)list_get_item(param_n, i); - /* printing security config */ - g_printf("security configuration:\r\n"); - g_printf("\tAllowRootLogin: %i\r\n",sc->allow_root); - g_printf("\tMaxLoginRetry: %i\r\n",sc->login_retry); - if (sc->ts_users_enable) - { - g_printf("\tTSUsersGroup: %i\r\n", sc->ts_users); - } - else - { - g_printf("\tNo TSUsersGroup defined\r\n"); - } - if (sc->ts_admins_enable) - { - g_printf("\tTSAdminsGroup: %i\r\n", sc->ts_admins); - } - else - { - g_printf("\tNo TSAdminsGroup defined\r\n"); - } + if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ALLOW_ROOT)) + { + sc->allow_root = text2bool((char *)list_get_item(param_v, i)); + } - return 0; + if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_LOGIN_RETRY)) + { + sc->login_retry = g_atoi((char *)list_get_item(param_v, i)); + } + + if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_USR_GROUP)) + { + if (g_getgroup_info((char *)list_get_item(param_v, i), &gid) == 0) + { + sc->ts_users_enable = 1; + sc->ts_users = gid; + } + } + + if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_ADM_GROUP)) + { + if (g_getgroup_info((char *)list_get_item(param_v, i), &gid) == 0) + { + sc->ts_admins_enable = 1; + sc->ts_admins = gid; + } + } + } + + /* printing security config */ + g_printf("security configuration:\r\n"); + g_printf("\tAllowRootLogin: %i\r\n", sc->allow_root); + g_printf("\tMaxLoginRetry: %i\r\n", sc->login_retry); + + if (sc->ts_users_enable) + { + g_printf("\tTSUsersGroup: %i\r\n", sc->ts_users); + } + else + { + g_printf("\tNo TSUsersGroup defined\r\n"); + } + + if (sc->ts_admins_enable) + { + g_printf("\tTSAdminsGroup: %i\r\n", sc->ts_admins); + } + else + { + g_printf("\tNo TSAdminsGroup defined\r\n"); + } + + return 0; } /******************************************************************************/ int DEFAULT_CC -config_read_sessions(int file, struct config_sessions* se, struct list* param_n, - struct list* param_v) +config_read_sessions(int file, struct config_sessions *se, struct list *param_n, + struct list *param_v) { - int i; - char* buf; + int i; + char *buf; - list_clear(param_v); - list_clear(param_n); + list_clear(param_v); + list_clear(param_n); - /* setting defaults */ - se->x11_display_offset=10; - se->max_sessions=0; - se->max_idle_time=0; - se->max_disc_time=0; - se->kill_disconnected=0; + /* setting defaults */ + se->x11_display_offset = 10; + se->max_sessions = 0; + se->max_idle_time = 0; + se->max_disc_time = 0; + se->kill_disconnected = 0; - file_read_section(file, SESMAN_CFG_SESSIONS, param_n, param_v); - for (i = 0; i < param_n->count; i++) - { - buf = (char*)list_get_item(param_n, i); - if (0 == g_strcasecmp(buf, SESMAN_CFG_X11DISPLAYOFFSET)) - { - se->x11_display_offset = g_atoi((char*)list_get_item(param_v, i)); - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_MAX)) - { - se->max_sessions = g_atoi((char*)list_get_item(param_v, i)); - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_KILL_DISC)) - { - se->kill_disconnected = text2bool((char*)list_get_item(param_v, i)); - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_IDLE_LIMIT)) - { - se->max_idle_time=g_atoi((char*)list_get_item(param_v, i)); - } - if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_DISC_LIMIT)) - { - se->max_disc_time=g_atoi((char*)list_get_item(param_v, i)); - } - } + file_read_section(file, SESMAN_CFG_SESSIONS, param_n, param_v); - /* printing security config */ - g_printf("session configuration:\r\n"); - g_printf("\tMaxSessions: %i\r\n", se->max_sessions); - g_printf("\tX11DisplayOffset: %i\r\n", se->x11_display_offset); - g_printf("\tKillDisconnected: %i\r\n", se->kill_disconnected); - g_printf("\tIdleTimeLimit: %i\r\n", se->max_idle_time); - g_printf("\tDisconnectedTimeLimit: %i\r\n", se->max_idle_time); + for (i = 0; i < param_n->count; i++) + { + buf = (char *)list_get_item(param_n, i); - return 0; + if (0 == g_strcasecmp(buf, SESMAN_CFG_X11DISPLAYOFFSET)) + { + se->x11_display_offset = g_atoi((char *)list_get_item(param_v, i)); + } + + if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_MAX)) + { + se->max_sessions = g_atoi((char *)list_get_item(param_v, i)); + } + + if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_KILL_DISC)) + { + se->kill_disconnected = text2bool((char *)list_get_item(param_v, i)); + } + + if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_IDLE_LIMIT)) + { + se->max_idle_time = g_atoi((char *)list_get_item(param_v, i)); + } + + if (0 == g_strcasecmp(buf, SESMAN_CFG_SESS_DISC_LIMIT)) + { + se->max_disc_time = g_atoi((char *)list_get_item(param_v, i)); + } + } + + /* printing security config */ + g_printf("session configuration:\r\n"); + g_printf("\tMaxSessions: %i\r\n", se->max_sessions); + g_printf("\tX11DisplayOffset: %i\r\n", se->x11_display_offset); + g_printf("\tKillDisconnected: %i\r\n", se->kill_disconnected); + g_printf("\tIdleTimeLimit: %i\r\n", se->max_idle_time); + g_printf("\tDisconnectedTimeLimit: %i\r\n", se->max_idle_time); + + return 0; } /******************************************************************************/ int DEFAULT_CC -config_read_rdp_params(int file, struct config_sesman* cs, struct list* param_n, - struct list* param_v) +config_read_rdp_params(int file, struct config_sesman *cs, struct list *param_n, + struct list *param_v) { - int i; + int i; - list_clear(param_v); - list_clear(param_n); + list_clear(param_v); + list_clear(param_n); - cs->rdp_params=list_create(); + cs->rdp_params = list_create(); - file_read_section(file, SESMAN_CFG_RDP_PARAMS, param_n, param_v); - for (i = 0; i < param_n->count; i++) - { - list_add_item(cs->rdp_params, (long)g_strdup((char*)list_get_item(param_v, i))); - } + file_read_section(file, SESMAN_CFG_RDP_PARAMS, param_n, param_v); - /* printing security config */ - g_printf("X11rdp parameters:\r\n"); - for (i = 0; i < cs->rdp_params->count; i++) - { - g_printf("\tParameter %02d %s\r\n", i, (char*)list_get_item(cs->rdp_params, i)); - } + for (i = 0; i < param_n->count; i++) + { + list_add_item(cs->rdp_params, (long)g_strdup((char *)list_get_item(param_v, i))); + } - return 0; + /* printing security config */ + g_printf("X11rdp parameters:\r\n"); + + for (i = 0; i < cs->rdp_params->count; i++) + { + g_printf("\tParameter %02d %s\r\n", i, (char *)list_get_item(cs->rdp_params, i)); + } + + return 0; } /******************************************************************************/ int DEFAULT_CC -config_read_vnc_params(int file, struct config_sesman* cs, struct list* param_n, - struct list* param_v) +config_read_vnc_params(int file, struct config_sesman *cs, struct list *param_n, + struct list *param_v) { - int i; + int i; - list_clear(param_v); - list_clear(param_n); + list_clear(param_v); + list_clear(param_n); - cs->vnc_params=list_create(); + cs->vnc_params = list_create(); - file_read_section(file, SESMAN_CFG_VNC_PARAMS, param_n, param_v); - for (i = 0; i < param_n->count; i++) - { - list_add_item(cs->vnc_params, (long)g_strdup((char*)list_get_item(param_v, i))); - } + file_read_section(file, SESMAN_CFG_VNC_PARAMS, param_n, param_v); - /* printing security config */ - g_printf("Xvnc parameters:\r\n"); - for (i = 0; i < cs->vnc_params->count; i++) - { - g_printf("\tParameter %02d %s\r\n", i, (char*)list_get_item(cs->vnc_params, i)); - } + for (i = 0; i < param_n->count; i++) + { + list_add_item(cs->vnc_params, (long)g_strdup((char *)list_get_item(param_v, i))); + } - return 0; + /* printing security config */ + g_printf("Xvnc parameters:\r\n"); + + for (i = 0; i < cs->vnc_params->count; i++) + { + g_printf("\tParameter %02d %s\r\n", i, (char *)list_get_item(cs->vnc_params, i)); + } + + return 0; } - diff --git a/sesman/config.h b/sesman/config.h index 73fab38f..72c6cac4 100644 --- a/sesman/config.h +++ b/sesman/config.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -296,4 +295,3 @@ config_read_vnc_params(int file, struct config_sesman* cs, struct list* param_n, struct list* param_v); #endif - diff --git a/sesman/env.c b/sesman/env.c index f7abe120..9f35f368 100644 --- a/sesman/env.c +++ b/sesman/env.c @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file env.c * @brief User environment handling code * @author Jay Sorg - * + * */ #include "sesman.h" @@ -31,95 +30,105 @@ #include "grp.h" extern unsigned char g_fixedkey[8]; /* in sesman.c */ -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ /******************************************************************************/ int DEFAULT_CC -env_check_password_file(char* filename, char* password) +env_check_password_file(char *filename, char *password) { - char encryptedPasswd[16]; - int fd; + char encryptedPasswd[16]; + int fd; - g_memset(encryptedPasswd, 0, 16); - g_strncpy(encryptedPasswd, password, 8); - rfbDesKey(g_fixedkey, 0); - rfbDes((unsigned char*)encryptedPasswd, (unsigned char*)encryptedPasswd); - fd = g_file_open(filename); - if (fd == -1) - { - log_message(LOG_LEVEL_WARNING, - "can't read vnc password file - %s", - filename); - return 1; - } - g_file_write(fd, encryptedPasswd, 8); - g_file_close(fd); - return 0; + g_memset(encryptedPasswd, 0, 16); + g_strncpy(encryptedPasswd, password, 8); + rfbDesKey(g_fixedkey, 0); + rfbDes((unsigned char *)encryptedPasswd, (unsigned char *)encryptedPasswd); + fd = g_file_open(filename); + + if (fd == -1) + { + log_message(LOG_LEVEL_WARNING, + "can't read vnc password file - %s", + filename); + return 1; + } + + g_file_write(fd, encryptedPasswd, 8); + g_file_close(fd); + return 0; } /******************************************************************************/ int DEFAULT_CC -env_set_user(char* username, char* passwd_file, int display) +env_set_user(char *username, char *passwd_file, int display) { - int error; - int pw_uid; - int pw_gid; - int uid; - char pw_shell[256]; - char pw_dir[256]; - char pw_gecos[256]; - char text[256]; + int error; + int pw_uid; + int pw_gid; + int uid; + char pw_shell[256]; + char pw_dir[256]; + char pw_gecos[256]; + char text[256]; + + error = g_getuser_info(username, &pw_gid, &pw_uid, pw_shell, pw_dir, + pw_gecos); - error = g_getuser_info(username, &pw_gid, &pw_uid, pw_shell, pw_dir, - pw_gecos); - if (error == 0) - { - g_rm_temp_dir(); - error = g_setgid(pw_gid); if (error == 0) { - error = g_initgroups(username, pw_gid); - } - if (error == 0) - { - uid = pw_uid; - error = g_setuid(uid); - } - g_mk_temp_dir(0); - if (error == 0) - { - g_clearenv(); - g_setenv("SHELL", pw_shell, 1); - g_setenv("PATH", "/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin", 1); - g_setenv("USER", username, 1); - g_sprintf(text, "%d", uid); - g_setenv("UID", text, 1); - g_setenv("HOME", pw_dir, 1); - g_set_current_dir(pw_dir); - g_sprintf(text, ":%d.0", display); - g_setenv("DISPLAY", text, 1); - if (passwd_file != 0) - { - if (0 == g_cfg->auth_file_path) + g_rm_temp_dir(); + error = g_setgid(pw_gid); + + if (error == 0) { - /* if no auth_file_path is set, then we go for - $HOME/.vnc/sesman_username_passwd */ - g_mkdir(".vnc"); - g_sprintf(passwd_file, "%s/.vnc/sesman_%s_passwd", pw_dir, username); + error = g_initgroups(username, pw_gid); } - else + + if (error == 0) { - /* we use auth_file_path as requested */ - g_sprintf(passwd_file, g_cfg->auth_file_path, username); + uid = pw_uid; + error = g_setuid(uid); + } + + g_mk_temp_dir(0); + + if (error == 0) + { + g_clearenv(); + g_setenv("SHELL", pw_shell, 1); + g_setenv("PATH", "/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin", 1); + g_setenv("USER", username, 1); + g_sprintf(text, "%d", uid); + g_setenv("UID", text, 1); + g_setenv("HOME", pw_dir, 1); + g_set_current_dir(pw_dir); + g_sprintf(text, ":%d.0", display); + g_setenv("DISPLAY", text, 1); + + if (passwd_file != 0) + { + if (0 == g_cfg->auth_file_path) + { + /* if no auth_file_path is set, then we go for + $HOME/.vnc/sesman_username_passwd */ + g_mkdir(".vnc"); + g_sprintf(passwd_file, "%s/.vnc/sesman_%s_passwd", pw_dir, username); + } + else + { + /* we use auth_file_path as requested */ + g_sprintf(passwd_file, g_cfg->auth_file_path, username); + } + + LOG_DBG("pass file: %s", passwd_file); + } } - LOG_DBG("pass file: %s", passwd_file); - } } - } - else - { - log_message(LOG_LEVEL_ERROR, - "error getting user info for user %s", username); - } - return error; + else + { + log_message(LOG_LEVEL_ERROR, + "error getting user info for user %s", username); + } + + return error; } diff --git a/sesman/env.h b/sesman/env.h index b14344af..c185ae30 100644 --- a/sesman/env.h +++ b/sesman/env.h @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file env.h * @brief User environment handling code declarations * @author Jay Sorg - * + * */ #ifndef ENV_H @@ -42,7 +41,7 @@ env_check_password_file(char* filename, char* password); /** * * @brief Sets user environment ($PATH, $HOME, $UID, and others) - * @param username Username + * @param username Username * @param passwd_file VNC password file * @param display The session display * @return 0 on success, g_getuser_info() error codes on error @@ -52,4 +51,3 @@ int DEFAULT_CC env_set_user(char* username, char* passwd_file, int display); #endif - diff --git a/sesman/libscp/libscp.h b/sesman/libscp/libscp.h index e06803cf..ed73380f 100644 --- a/sesman/libscp/libscp.h +++ b/sesman/libscp/libscp.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_commands.h b/sesman/libscp/libscp_commands.h index 8745c6bf..8c8d5f08 100644 --- a/sesman/libscp/libscp_commands.h +++ b/sesman/libscp/libscp_commands.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_commands_mng.h b/sesman/libscp/libscp_commands_mng.h index 78dffcf4..e1d6ba7c 100644 --- a/sesman/libscp/libscp_commands_mng.h +++ b/sesman/libscp/libscp_commands_mng.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_connection.c b/sesman/libscp/libscp_connection.c index bf49fb84..6366d51a 100644 --- a/sesman/libscp/libscp_connection.c +++ b/sesman/libscp/libscp_connection.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -29,32 +28,32 @@ //extern struct log_config* s_log; -struct SCP_CONNECTION* +struct SCP_CONNECTION * scp_connection_create(int sck) { - struct SCP_CONNECTION* conn; + struct SCP_CONNECTION *conn; - conn = g_malloc(sizeof(struct SCP_CONNECTION), 0); + conn = g_malloc(sizeof(struct SCP_CONNECTION), 0); - if (0 == conn) - { - log_message(LOG_LEVEL_WARNING, "[connection:%d] connection create: malloc error", __LINE__); - return 0; - } + if (0 == conn) + { + log_message(LOG_LEVEL_WARNING, "[connection:%d] connection create: malloc error", __LINE__); + return 0; + } - conn->in_sck=sck; - make_stream(conn->in_s); - init_stream(conn->in_s, 8196); - make_stream(conn->out_s); - init_stream(conn->out_s, 8196); + conn->in_sck = sck; + make_stream(conn->in_s); + init_stream(conn->in_s, 8196); + make_stream(conn->out_s); + init_stream(conn->out_s, 8196); - return conn; + return conn; } void -scp_connection_destroy(struct SCP_CONNECTION* c) +scp_connection_destroy(struct SCP_CONNECTION *c) { - free_stream(c->in_s); - free_stream(c->out_s); - g_free(c); + free_stream(c->in_s); + free_stream(c->out_s); + g_free(c); } diff --git a/sesman/libscp/libscp_connection.h b/sesman/libscp/libscp_connection.h index ba94f429..e5bdbe27 100644 --- a/sesman/libscp/libscp_connection.h +++ b/sesman/libscp/libscp_connection.h @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file libscp_connection.h * @brief SCP_CONNECTION handling code * @author Simone Fedele - * + * */ #ifndef LIBSCP_CONNECTION_H @@ -37,7 +36,7 @@ * * @return a struct SCP_CONNECTION* object on success, NULL otherwise * - */ + */ struct SCP_CONNECTION* scp_connection_create(int sck); @@ -45,10 +44,9 @@ scp_connection_create(int sck); * * @brief destroys a struct SCP_CONNECTION* object * @param c the object to be destroyed - * + * */ void scp_connection_destroy(struct SCP_CONNECTION* c); #endif - diff --git a/sesman/libscp/libscp_init.c b/sesman/libscp/libscp_init.c index 4c48fb1f..eae57c6e 100644 --- a/sesman/libscp/libscp_init.c +++ b/sesman/libscp/libscp_init.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -33,19 +32,18 @@ int DEFAULT_CC scp_init() { -/* - if (0 == log) - { - return 1; - } -*/ + /* + if (0 == log) + { + return 1; + } + */ - //s_log = log; + //s_log = log; - scp_lock_init(); + scp_lock_init(); - log_message(LOG_LEVEL_WARNING, "[init:%d] libscp initialized", __LINE__); + log_message(LOG_LEVEL_WARNING, "[init:%d] libscp initialized", __LINE__); - return 0; + return 0; } - diff --git a/sesman/libscp/libscp_init.h b/sesman/libscp/libscp_init.h index 92dbc659..20a75857 100644 --- a/sesman/libscp/libscp_init.h +++ b/sesman/libscp/libscp_init.h @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file libscp_init.h * @brief libscp initialization code header * @author Simone Fedele - * + * */ #ifndef LIBSCP_INIT_H @@ -41,8 +40,7 @@ * It this memory needs to be g_free()d * */ -int DEFAULT_CC +int DEFAULT_CC scp_init(); #endif - diff --git a/sesman/libscp/libscp_lock.c b/sesman/libscp/libscp_lock.c index 9556b872..4db05422 100644 --- a/sesman/libscp/libscp_lock.c +++ b/sesman/libscp/libscp_lock.c @@ -1,25 +1,23 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - session manager - linux only - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * session manager + * linux only + */ #include "libscp_lock.h" @@ -37,110 +35,114 @@ int lock_fork_waiting_count; /* threads suspended until the fork finish void DEFAULT_CC scp_lock_init(void) { - /* initializing fork lock */ - pthread_mutexattr_init(&lock_fork_attr); - pthread_mutex_init(&lock_fork, &lock_fork_attr); - sem_init(&lock_fork_req, 0, 0); - sem_init(&lock_fork_wait, 0, 0); + /* initializing fork lock */ + pthread_mutexattr_init(&lock_fork_attr); + pthread_mutex_init(&lock_fork, &lock_fork_attr); + sem_init(&lock_fork_req, 0, 0); + sem_init(&lock_fork_wait, 0, 0); - /* here we don't use locking because lock_init() should be called BEFORE */ - /* any thread is created */ - lock_fork_blockers_count=0; - lock_fork_waiting_count=0; - lock_fork_forkers_count=0; + /* here we don't use locking because lock_init() should be called BEFORE */ + /* any thread is created */ + lock_fork_blockers_count = 0; + lock_fork_waiting_count = 0; + lock_fork_forkers_count = 0; } /******************************************************************************/ void DEFAULT_CC scp_lock_fork_request(void) { - /* lock mutex */ - pthread_mutex_lock(&lock_fork); - if (lock_fork_blockers_count == 0) - { - /* if noone is blocking fork(), then we're allowed to fork */ - sem_post(&lock_fork_req); - } - lock_fork_forkers_count++; - pthread_mutex_unlock(&lock_fork); + /* lock mutex */ + pthread_mutex_lock(&lock_fork); - /* we wait to be allowed to fork() */ - sem_wait(&lock_fork_req); + if (lock_fork_blockers_count == 0) + { + /* if noone is blocking fork(), then we're allowed to fork */ + sem_post(&lock_fork_req); + } + + lock_fork_forkers_count++; + pthread_mutex_unlock(&lock_fork); + + /* we wait to be allowed to fork() */ + sem_wait(&lock_fork_req); } /******************************************************************************/ void DEFAULT_CC scp_lock_fork_release(void) { - pthread_mutex_lock(&lock_fork); - lock_fork_forkers_count--; + pthread_mutex_lock(&lock_fork); + lock_fork_forkers_count--; - /* if there's someone else that want to fork, we let him fork() */ - if (lock_fork_forkers_count > 0) - { - sem_post(&lock_fork_req); - } + /* if there's someone else that want to fork, we let him fork() */ + if (lock_fork_forkers_count > 0) + { + sem_post(&lock_fork_req); + } - for (;lock_fork_waiting_count > 0; lock_fork_waiting_count--) - { - /* waking up the other processes */ - sem_post(&lock_fork_wait); - } - pthread_mutex_unlock(&lock_fork); + for (; lock_fork_waiting_count > 0; lock_fork_waiting_count--) + { + /* waking up the other processes */ + sem_post(&lock_fork_wait); + } + + pthread_mutex_unlock(&lock_fork); } /******************************************************************************/ void DEFAULT_CC scp_lock_fork_critical_section_end(int blocking) { - //LOG_DBG("lock_fork_critical_secection_end()",0); - /* lock mutex */ - pthread_mutex_lock(&lock_fork); + //LOG_DBG("lock_fork_critical_secection_end()",0); + /* lock mutex */ + pthread_mutex_lock(&lock_fork); - if (blocking == LIBSCP_LOCK_FORK_BLOCKER) - { - lock_fork_blockers_count--; - } + if (blocking == LIBSCP_LOCK_FORK_BLOCKER) + { + lock_fork_blockers_count--; + } - /* if there's someone who wants to fork and we're the last blocking */ - /* then we let him go */ - if ((lock_fork_blockers_count == 0) && (lock_fork_forkers_count>0)) - { - sem_post(&lock_fork_req); - } - pthread_mutex_unlock(&lock_fork); + /* if there's someone who wants to fork and we're the last blocking */ + /* then we let him go */ + if ((lock_fork_blockers_count == 0) && (lock_fork_forkers_count > 0)) + { + sem_post(&lock_fork_req); + } + + pthread_mutex_unlock(&lock_fork); } /******************************************************************************/ int DEFAULT_CC scp_lock_fork_critical_section_start(void) { - //LOG_DBG("lock_fork_critical_secection_start()",0); - do - { - pthread_mutex_lock(&lock_fork); - - /* someone requested to fork */ - if (lock_fork_forkers_count > 0) + //LOG_DBG("lock_fork_critical_secection_start()",0); + do { - lock_fork_waiting_count++; - pthread_mutex_unlock(&lock_fork); + pthread_mutex_lock(&lock_fork); - /* we wait until the fork finishes */ - sem_wait(&lock_fork_wait); + /* someone requested to fork */ + if (lock_fork_forkers_count > 0) + { + lock_fork_waiting_count++; + pthread_mutex_unlock(&lock_fork); + /* we wait until the fork finishes */ + sem_wait(&lock_fork_wait); + + } + else + { + /* no fork, so we can go on... */ + lock_fork_blockers_count++; + pthread_mutex_unlock(&lock_fork); + + return LIBSCP_LOCK_FORK_BLOCKER; + } } - else - { - /* no fork, so we can go on... */ - lock_fork_blockers_count++; - pthread_mutex_unlock(&lock_fork); + while (1); - return LIBSCP_LOCK_FORK_BLOCKER; - } - } while (1); - - /* we'll never get here */ - return LIBSCP_LOCK_FORK_WAITING; + /* we'll never get here */ + return LIBSCP_LOCK_FORK_WAITING; } - diff --git a/sesman/libscp/libscp_lock.h b/sesman/libscp/libscp_lock.h index 5c96cc5b..b4e93c52 100644 --- a/sesman/libscp/libscp_lock.h +++ b/sesman/libscp/libscp_lock.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef LIBSCP_LOCK_H #define LIBSCP_LOCK_H @@ -72,4 +71,3 @@ void DEFAULT_CC scp_lock_fork_critical_section_end(int blocking); #endif - diff --git a/sesman/libscp/libscp_session.c b/sesman/libscp/libscp_session.c index 3ed5070a..4c389655 100644 --- a/sesman/libscp/libscp_session.c +++ b/sesman/libscp/libscp_session.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -34,379 +33,425 @@ //extern struct log_config* s_log; /*******************************************************************/ -struct SCP_SESSION* +struct SCP_SESSION * scp_session_create() { - struct SCP_SESSION* s; + struct SCP_SESSION *s; + + s = (struct SCP_SESSION *)g_malloc(sizeof(struct SCP_SESSION), 1); + + if (0 == s) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] session create: malloc error", __LINE__); + return 0; + } + + return s; +} + +/*******************************************************************/ +int +scp_session_set_type(struct SCP_SESSION *s, tui8 type) +{ + switch (type) + { + case SCP_SESSION_TYPE_XVNC: + s->type = SCP_SESSION_TYPE_XVNC; + break; + case SCP_SESSION_TYPE_XRDP: + s->type = SCP_SESSION_TYPE_XRDP; + break; + case SCP_GW_AUTHENTICATION: + s->type = SCP_GW_AUTHENTICATION; + break; + case SCP_SESSION_TYPE_MANAGE: + s->type = SCP_SESSION_TYPE_MANAGE; + s->mng = (struct SCP_MNG_DATA *)g_malloc(sizeof(struct SCP_MNG_DATA), 1); + + if (NULL == s->mng) + { + log_message(LOG_LEVEL_ERROR, "[session:%d] set_type: internal error", __LINE__); + return 1; + } + + break; + default: + log_message(LOG_LEVEL_WARNING, "[session:%d] set_type: unknown type", __LINE__); + return 1; + } - s = (struct SCP_SESSION*)g_malloc(sizeof(struct SCP_SESSION), 1); - if (0 == s) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] session create: malloc error", __LINE__); return 0; - } - return s; } /*******************************************************************/ int -scp_session_set_type(struct SCP_SESSION* s, tui8 type) +scp_session_set_version(struct SCP_SESSION *s, tui32 version) { - switch (type) - { - case SCP_SESSION_TYPE_XVNC: - s->type = SCP_SESSION_TYPE_XVNC; - break; - case SCP_SESSION_TYPE_XRDP: - s->type = SCP_SESSION_TYPE_XRDP; - break; - case SCP_GW_AUTHENTICATION: - s->type = SCP_GW_AUTHENTICATION; - break; - case SCP_SESSION_TYPE_MANAGE: - s->type = SCP_SESSION_TYPE_MANAGE; - s->mng = (struct SCP_MNG_DATA*)g_malloc(sizeof(struct SCP_MNG_DATA), 1); - if (NULL == s->mng) - { - log_message(LOG_LEVEL_ERROR, "[session:%d] set_type: internal error", __LINE__); + switch (version) + { + case 0: + s->version = 0; + break; + case 1: + s->version = 1; + break; + default: + log_message(LOG_LEVEL_WARNING, "[session:%d] set_version: unknown version", __LINE__); + return 1; + } + + return 0; +} + +/*******************************************************************/ +int +scp_session_set_height(struct SCP_SESSION *s, tui16 h) +{ + s->height = h; + return 0; +} + +/*******************************************************************/ +int +scp_session_set_width(struct SCP_SESSION *s, tui16 w) +{ + s->width = w; + return 0; +} + +/*******************************************************************/ +int +scp_session_set_bpp(struct SCP_SESSION *s, tui8 bpp) +{ + switch (bpp) + { + case 8: + case 15: + case 16: + case 24: + s->bpp = bpp; + default: + return 1; + } + + return 0; +} + +/*******************************************************************/ +int +scp_session_set_rsr(struct SCP_SESSION *s, tui8 rsr) +{ + if (s->rsr) + { + s->rsr = 1; + } + else + { + s->rsr = 0; + } + + return 0; +} + +/*******************************************************************/ +int +scp_session_set_locale(struct SCP_SESSION *s, char *str) +{ + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_locale: null locale", __LINE__); + s->locale[0] = '\0'; return 1; - } - break; - default: - log_message(LOG_LEVEL_WARNING, "[session:%d] set_type: unknown type", __LINE__); - return 1; - } - return 0; + } + + g_strncpy(s->locale, str, 17); + s->locale[17] = '\0'; + return 0; } /*******************************************************************/ int -scp_session_set_version(struct SCP_SESSION* s, tui32 version) +scp_session_set_username(struct SCP_SESSION *s, char *str) { - switch (version) - { - case 0: - s->version = 0; - break; - case 1: - s->version = 1; - break; - default: - log_message(LOG_LEVEL_WARNING, "[session:%d] set_version: unknown version", __LINE__); - return 1; - } - return 0; + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_username: null username", __LINE__); + return 1; + } + + if (0 != s->username) + { + g_free(s->username); + } + + s->username = g_strdup(str); + + if (0 == s->username) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_username: strdup error", __LINE__); + return 1; + } + + return 0; } /*******************************************************************/ int -scp_session_set_height(struct SCP_SESSION* s, tui16 h) +scp_session_set_password(struct SCP_SESSION *s, char *str) { - s->height = h; - return 0; + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_password: null password", __LINE__); + return 1; + } + + if (0 != s->password) + { + g_free(s->password); + } + + s->password = g_strdup(str); + + if (0 == s->password) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_password: strdup error", __LINE__); + return 1; + } + + return 0; } /*******************************************************************/ int -scp_session_set_width(struct SCP_SESSION* s, tui16 w) +scp_session_set_domain(struct SCP_SESSION *s, char *str) { - s->width = w; - return 0; + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_domain: null domain", __LINE__); + return 1; + } + + if (0 != s->domain) + { + g_free(s->domain); + } + + s->domain = g_strdup(str); + + if (0 == s->domain) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_domain: strdup error", __LINE__); + return 1; + } + + return 0; } /*******************************************************************/ int -scp_session_set_bpp(struct SCP_SESSION* s, tui8 bpp) +scp_session_set_program(struct SCP_SESSION *s, char *str) { - switch (bpp) - { - case 8: - case 15: - case 16: - case 24: - s->bpp = bpp; - default: - return 1; - } - return 0; + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_program: null program", __LINE__); + return 1; + } + + if (0 != s->program) + { + g_free(s->program); + } + + s->program = g_strdup(str); + + if (0 == s->program) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_program: strdup error", __LINE__); + return 1; + } + + return 0; } /*******************************************************************/ int -scp_session_set_rsr(struct SCP_SESSION* s, tui8 rsr) +scp_session_set_directory(struct SCP_SESSION *s, char *str) { - if (s->rsr) - { - s->rsr = 1; - } - else - { - s->rsr = 0; - } - return 0; + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_directory: null directory", __LINE__); + return 1; + } + + if (0 != s->directory) + { + g_free(s->directory); + } + + s->directory = g_strdup(str); + + if (0 == s->directory) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_directory: strdup error", __LINE__); + return 1; + } + + return 0; } /*******************************************************************/ int -scp_session_set_locale(struct SCP_SESSION* s, char* str) +scp_session_set_client_ip(struct SCP_SESSION *s, char *str) { - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_locale: null locale", __LINE__); - s->locale[0]='\0'; - return 1; - } - g_strncpy(s->locale, str, 17); - s->locale[17]='\0'; - return 0; + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_client_ip: null ip", __LINE__); + return 1; + } + + if (0 != s->client_ip) + { + g_free(s->client_ip); + } + + s->client_ip = g_strdup(str); + + if (0 == s->client_ip) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_client_ip: strdup error", __LINE__); + return 1; + } + + return 0; } /*******************************************************************/ int -scp_session_set_username(struct SCP_SESSION* s, char* str) +scp_session_set_hostname(struct SCP_SESSION *s, char *str) { - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_username: null username", __LINE__); - return 1; - } - if (0 != s->username) - { - g_free(s->username); - } - s->username = g_strdup(str); - if (0 == s->username) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_username: strdup error", __LINE__); - return 1; - } - return 0; + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_hostname: null hostname", __LINE__); + return 1; + } + + if (0 != s->hostname) + { + g_free(s->hostname); + } + + s->hostname = g_strdup(str); + + if (0 == s->hostname) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_hostname: strdup error", __LINE__); + return 1; + } + + return 0; } /*******************************************************************/ int -scp_session_set_password(struct SCP_SESSION* s, char* str) +scp_session_set_errstr(struct SCP_SESSION *s, char *str) { - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_password: null password", __LINE__); - return 1; - } - if (0 != s->password) - { - g_free(s->password); - } - s->password = g_strdup(str); - if (0 == s->password) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_password: strdup error", __LINE__); - return 1; - } - return 0; + if (0 == str) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_errstr: null string", __LINE__); + return 1; + } + + if (0 != s->errstr) + { + g_free(s->errstr); + } + + s->errstr = g_strdup(str); + + if (0 == s->errstr) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_errstr: strdup error", __LINE__); + return 1; + } + + return 0; } /*******************************************************************/ int -scp_session_set_domain(struct SCP_SESSION* s, char* str) +scp_session_set_display(struct SCP_SESSION *s, SCP_DISPLAY display) { - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_domain: null domain", __LINE__); - return 1; - } - if (0 != s->domain) - { - g_free(s->domain); - } - s->domain = g_strdup(str); - if (0 == s->domain) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_domain: strdup error", __LINE__); - return 1; - } - return 0; + s->display = display; + return 0; } /*******************************************************************/ int -scp_session_set_program(struct SCP_SESSION* s, char* str) +scp_session_set_addr(struct SCP_SESSION *s, int type, void *addr) { - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_program: null program", __LINE__); - return 1; - } - if (0 != s->program) - { - g_free(s->program); - } - s->program = g_strdup(str); - if (0 == s->program) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_program: strdup error", __LINE__); - return 1; - } - return 0; -} - -/*******************************************************************/ -int -scp_session_set_directory(struct SCP_SESSION* s, char* str) -{ - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_directory: null directory", __LINE__); - return 1; - } - if (0 != s->directory) - { - g_free(s->directory); - } - s->directory = g_strdup(str); - if (0 == s->directory) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_directory: strdup error", __LINE__); - return 1; - } - return 0; -} - -/*******************************************************************/ -int -scp_session_set_client_ip(struct SCP_SESSION* s, char* str) -{ - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_client_ip: null ip", __LINE__); - return 1; - } - if (0 != s->client_ip) - { - g_free(s->client_ip); - } - s->client_ip = g_strdup(str); - if (0 == s->client_ip) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_client_ip: strdup error", __LINE__); - return 1; - } - return 0; -} - -/*******************************************************************/ -int -scp_session_set_hostname(struct SCP_SESSION* s, char* str) -{ - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_hostname: null hostname", __LINE__); - return 1; - } - if (0 != s->hostname) - { - g_free(s->hostname); - } - s->hostname = g_strdup(str); - if (0 == s->hostname) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_hostname: strdup error", __LINE__); - return 1; - } - return 0; -} - -/*******************************************************************/ -int -scp_session_set_errstr(struct SCP_SESSION* s, char* str) -{ - if (0 == str) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_errstr: null string", __LINE__); - return 1; - } - if (0 != s->errstr) - { - g_free(s->errstr); - } - s->errstr = g_strdup(str); - if (0 == s->errstr) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_errstr: strdup error", __LINE__); - return 1; - } - return 0; -} - -/*******************************************************************/ -int -scp_session_set_display(struct SCP_SESSION* s, SCP_DISPLAY display) -{ - s->display = display; - return 0; -} - -/*******************************************************************/ -int -scp_session_set_addr(struct SCP_SESSION* s, int type, void* addr) -{ - struct in_addr ip4; + struct in_addr ip4; #ifdef IN6ADDR_ANY_INIT - struct in6_addr ip6; + struct in6_addr ip6; #endif - int ret; + int ret; - switch (type) - { - case SCP_ADDRESS_TYPE_IPV4: - /* convert from char to 32bit*/ - ret = inet_pton(AF_INET, addr, &ip4); - if (ret == 0) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_addr: invalid address", __LINE__); - inet_pton(AF_INET, "127.0.0.1", &ip4); - g_memcpy(&(s->ipv4addr), &(ip4.s_addr), 4); - return 1; - } - g_memcpy(&(s->ipv4addr), &(ip4.s_addr), 4); - break; - case SCP_ADDRESS_TYPE_IPV4_BIN: - g_memcpy(&(s->ipv4addr), addr, 4); - break; + switch (type) + { + case SCP_ADDRESS_TYPE_IPV4: + /* convert from char to 32bit*/ + ret = inet_pton(AF_INET, addr, &ip4); + + if (ret == 0) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_addr: invalid address", __LINE__); + inet_pton(AF_INET, "127.0.0.1", &ip4); + g_memcpy(&(s->ipv4addr), &(ip4.s_addr), 4); + return 1; + } + + g_memcpy(&(s->ipv4addr), &(ip4.s_addr), 4); + break; + case SCP_ADDRESS_TYPE_IPV4_BIN: + g_memcpy(&(s->ipv4addr), addr, 4); + break; #ifdef IN6ADDR_ANY_INIT - case SCP_ADDRESS_TYPE_IPV6: - /* convert from char to 128bit*/ - ret = inet_pton(AF_INET6, addr, &ip6); - if (ret == 0) - { - log_message(LOG_LEVEL_WARNING, "[session:%d] set_addr: invalid address", __LINE__); - inet_pton(AF_INET, "::1", &ip6); - g_memcpy(s->ipv6addr, &(ip6.s6_addr), 16); - return 1; - } - g_memcpy(s->ipv6addr, &(ip6.s6_addr), 16); - break; - case SCP_ADDRESS_TYPE_IPV6_BIN: - g_memcpy(s->ipv6addr, addr, 16); - break; + case SCP_ADDRESS_TYPE_IPV6: + /* convert from char to 128bit*/ + ret = inet_pton(AF_INET6, addr, &ip6); + + if (ret == 0) + { + log_message(LOG_LEVEL_WARNING, "[session:%d] set_addr: invalid address", __LINE__); + inet_pton(AF_INET, "::1", &ip6); + g_memcpy(s->ipv6addr, &(ip6.s6_addr), 16); + return 1; + } + + g_memcpy(s->ipv6addr, &(ip6.s6_addr), 16); + break; + case SCP_ADDRESS_TYPE_IPV6_BIN: + g_memcpy(s->ipv6addr, addr, 16); + break; #endif - default: - return 1; - } - return 0; + default: + return 1; + } + + return 0; } /*******************************************************************/ void -scp_session_destroy(struct SCP_SESSION* s) +scp_session_destroy(struct SCP_SESSION *s) { - g_free(s->username); - g_free(s->password); - g_free(s->hostname); - g_free(s->domain); - g_free(s->program); - g_free(s->directory); - g_free(s->client_ip); - g_free(s->errstr); - g_free(s->mng); - g_free(s); + g_free(s->username); + g_free(s->password); + g_free(s->hostname); + g_free(s->domain); + g_free(s->program); + g_free(s->directory); + g_free(s->client_ip); + g_free(s->errstr); + g_free(s->mng); + g_free(s); } diff --git a/sesman/libscp/libscp_session.h b/sesman/libscp/libscp_session.h index f5fe413e..b545af9e 100644 --- a/sesman/libscp/libscp_session.h +++ b/sesman/libscp/libscp_session.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_tcp.c b/sesman/libscp/libscp_tcp.c index 459992fe..29870563 100644 --- a/sesman/libscp/libscp_tcp.c +++ b/sesman/libscp/libscp_tcp.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -33,102 +32,103 @@ #include #include -extern struct log_config* s_log; +extern struct log_config *s_log; /*****************************************************************************/ int DEFAULT_CC -scp_tcp_force_recv(int sck, char* data, int len) +scp_tcp_force_recv(int sck, char *data, int len) { - int rcvd; - int block; + int rcvd; + int block; - LOG_DBG("scp_tcp_force_recv()"); - block = scp_lock_fork_critical_section_start(); + LOG_DBG("scp_tcp_force_recv()"); + block = scp_lock_fork_critical_section_start(); - while (len > 0) - { - rcvd = g_tcp_recv(sck, data, len, 0); - if (rcvd == -1) + while (len > 0) { - if (g_tcp_last_error_would_block(sck)) - { - g_sleep(1); - } - else - { - scp_lock_fork_critical_section_end(block); - return 1; - } - } - else if (rcvd == 0) - { - scp_lock_fork_critical_section_end(block); - return 1; - } - else - { - data += rcvd; - len -= rcvd; - } - } + rcvd = g_tcp_recv(sck, data, len, 0); - scp_lock_fork_critical_section_end(block); + if (rcvd == -1) + { + if (g_tcp_last_error_would_block(sck)) + { + g_sleep(1); + } + else + { + scp_lock_fork_critical_section_end(block); + return 1; + } + } + else if (rcvd == 0) + { + scp_lock_fork_critical_section_end(block); + return 1; + } + else + { + data += rcvd; + len -= rcvd; + } + } - return 0; + scp_lock_fork_critical_section_end(block); + + return 0; } /*****************************************************************************/ int DEFAULT_CC -scp_tcp_force_send(int sck, char* data, int len) +scp_tcp_force_send(int sck, char *data, int len) { - int sent; - int block; + int sent; + int block; - LOG_DBG("scp_tcp_force_send()"); - block = scp_lock_fork_critical_section_start(); + LOG_DBG("scp_tcp_force_send()"); + block = scp_lock_fork_critical_section_start(); - while (len > 0) - { - sent = g_tcp_send(sck, data, len, 0); - if (sent == -1) + while (len > 0) { - if (g_tcp_last_error_would_block(sck)) - { - g_sleep(1); - } - else - { - scp_lock_fork_critical_section_end(block); - return 1; - } - } - else if (sent == 0) - { - scp_lock_fork_critical_section_end(block); - return 1; - } - else - { - data += sent; - len -= sent; - } - } + sent = g_tcp_send(sck, data, len, 0); - scp_lock_fork_critical_section_end(block); + if (sent == -1) + { + if (g_tcp_last_error_would_block(sck)) + { + g_sleep(1); + } + else + { + scp_lock_fork_critical_section_end(block); + return 1; + } + } + else if (sent == 0) + { + scp_lock_fork_critical_section_end(block); + return 1; + } + else + { + data += sent; + len -= sent; + } + } - return 0; + scp_lock_fork_critical_section_end(block); + + return 0; } /*****************************************************************************/ int DEFAULT_CC -scp_tcp_bind(int sck, char* addr, char* port) +scp_tcp_bind(int sck, char *addr, char *port) { - struct sockaddr_in s; + struct sockaddr_in s; - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons(atoi(port)); - s.sin_addr.s_addr = inet_addr(addr); - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons(atoi(port)); + s.sin_addr.s_addr = inet_addr(addr); + return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); } - diff --git a/sesman/libscp/libscp_tcp.h b/sesman/libscp/libscp_tcp.h index 985984dc..1db70797 100644 --- a/sesman/libscp/libscp_tcp.h +++ b/sesman/libscp/libscp_tcp.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_types.h b/sesman/libscp/libscp_types.h index e6521741..2140eced 100644 --- a/sesman/libscp/libscp_types.h +++ b/sesman/libscp/libscp_types.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -43,7 +42,7 @@ #define SCP_SESSION_TYPE_XRDP 0x01 #define SCP_SESSION_TYPE_MANAGE 0x02 /* SCP_GW_AUTHENTICATION can be used when XRDP + sesman act as a gateway - * XRDP sends this command to let sesman verify if the user is allowed + * XRDP sends this command to let sesman verify if the user is allowed * to use the gateway */ #define SCP_GW_AUTHENTICATION 0x04 diff --git a/sesman/libscp/libscp_types_mng.h b/sesman/libscp/libscp_types_mng.h index e34dd413..e0edad55 100644 --- a/sesman/libscp/libscp_types_mng.h +++ b/sesman/libscp/libscp_types_mng.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_v0.c b/sesman/libscp/libscp_v0.c index f8b5a9d6..afa09bd8 100644 --- a/sesman/libscp/libscp_v0.c +++ b/sesman/libscp/libscp_v0.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -29,361 +28,386 @@ #include "os_calls.h" -extern struct log_config* s_log; +extern struct log_config *s_log; /* client API */ /******************************************************************************/ enum SCP_CLIENT_STATES_E -scp_v0c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +scp_v0c_connect(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - tui32 version; - tui32 size; - tui16 sz; + tui32 version; + tui32 size; + tui16 sz; - init_stream(c->in_s, c->in_s->size); - init_stream(c->out_s, c->in_s->size); + init_stream(c->in_s, c->in_s->size); + init_stream(c->out_s, c->in_s->size); - LOG_DBG("[v0:%d] starting connection", __LINE__); - g_tcp_set_non_blocking(c->in_sck); - g_tcp_set_no_delay(c->in_sck); - s_push_layer(c->out_s, channel_hdr, 8); + LOG_DBG("[v0:%d] starting connection", __LINE__); + g_tcp_set_non_blocking(c->in_sck); + g_tcp_set_no_delay(c->in_sck); + s_push_layer(c->out_s, channel_hdr, 8); - /* code */ - if (s->type == SCP_SESSION_TYPE_XVNC) - { - out_uint16_be(c->out_s, 0); - } - else if (s->type == SCP_SESSION_TYPE_XRDP) - { - out_uint16_be(c->out_s, 10); - } - else - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_INTERNAL_ERR; - } - sz = g_strlen(s->username); - out_uint16_be(c->out_s, sz); - out_uint8a(c->out_s, s->username, sz); + /* code */ + if (s->type == SCP_SESSION_TYPE_XVNC) + { + out_uint16_be(c->out_s, 0); + } + else if (s->type == SCP_SESSION_TYPE_XRDP) + { + out_uint16_be(c->out_s, 10); + } + else + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_INTERNAL_ERR; + } - sz = g_strlen(s->password); - out_uint16_be(c->out_s,sz); - out_uint8a(c->out_s, s->password, sz); - out_uint16_be(c->out_s, s->width); - out_uint16_be(c->out_s, s->height); - out_uint16_be(c->out_s, s->bpp); + sz = g_strlen(s->username); + out_uint16_be(c->out_s, sz); + out_uint8a(c->out_s, s->username, sz); - s_mark_end(c->out_s); - s_pop_layer(c->out_s, channel_hdr); + sz = g_strlen(s->password); + out_uint16_be(c->out_s, sz); + out_uint8a(c->out_s, s->password, sz); + out_uint16_be(c->out_s, s->width); + out_uint16_be(c->out_s, s->height); + out_uint16_be(c->out_s, s->bpp); - /* version */ - out_uint32_be(c->out_s, 0); - /* size */ - out_uint32_be(c->out_s, c->out_s->end - c->out_s->data); + s_mark_end(c->out_s); + s_pop_layer(c->out_s, channel_hdr); - if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; - } + /* version */ + out_uint32_be(c->out_s, 0); + /* size */ + out_uint32_be(c->out_s, c->out_s->end - c->out_s->data); - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; + } - in_uint32_be(c->in_s, version); - if (0 != version) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__); - return SCP_CLIENT_STATE_VERSION_ERR; - } + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; + } - in_uint32_be(c->in_s, size); - if (size < 14) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: packet size error", __LINE__); - return SCP_CLIENT_STATE_SIZE_ERR; - } + in_uint32_be(c->in_s, version); - /* getting payload */ - init_stream(c->in_s, c->in_s->size); - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (0 != version) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__); + return SCP_CLIENT_STATE_VERSION_ERR; + } - /* check code */ - in_uint16_be(c->in_s, sz); - if (3 != sz) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__); - return SCP_CLIENT_STATE_SEQUENCE_ERR; - } + in_uint32_be(c->in_s, size); - /* message payload */ - in_uint16_be(c->in_s, sz); - if (1 != sz) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: connection denied", __LINE__); - return SCP_CLIENT_STATE_CONNECTION_DENIED; - } + if (size < 14) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: packet size error", __LINE__); + return SCP_CLIENT_STATE_SIZE_ERR; + } - in_uint16_be(c->in_s, sz); - s->display = sz; + /* getting payload */ + init_stream(c->in_s, c->in_s->size); - LOG_DBG("[v0:%d] connection terminated", __LINE__); - return SCP_CLIENT_STATE_END; + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + /* check code */ + in_uint16_be(c->in_s, sz); + + if (3 != sz) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__); + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + /* message payload */ + in_uint16_be(c->in_s, sz); + + if (1 != sz) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: connection denied", __LINE__); + return SCP_CLIENT_STATE_CONNECTION_DENIED; + } + + in_uint16_be(c->in_s, sz); + s->display = sz; + + LOG_DBG("[v0:%d] connection terminated", __LINE__); + return SCP_CLIENT_STATE_END; } /* server API */ /******************************************************************************/ enum SCP_SERVER_STATES_E -scp_v0s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk) +scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk) { - tui32 version = 0; - tui32 size; - struct SCP_SESSION* session = 0; - tui16 sz; - tui32 code = 0; - char buf[257]; + tui32 version = 0; + tui32 size; + struct SCP_SESSION *session = 0; + tui16 sz; + tui32 code = 0; + char buf[257]; - if (!skipVchk) - { - LOG_DBG("[v0:%d] starting connection", __LINE__); - if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + if (!skipVchk) { - c->in_s->end = c->in_s->data + 8; - in_uint32_be(c->in_s, version); - if (version != 0) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__); - return SCP_SERVER_STATE_VERSION_ERR; - } + LOG_DBG("[v0:%d] starting connection", __LINE__); + + if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + c->in_s->end = c->in_s->data + 8; + in_uint32_be(c->in_s, version); + + if (version != 0) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__); + return SCP_SERVER_STATE_VERSION_ERR; + } + } + else + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + } + + in_uint32_be(c->in_s, size); + + init_stream(c->in_s, 8196); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + c->in_s->end = c->in_s->data + (size - 8); + + in_uint16_be(c->in_s, code); + + if (code == 0 || code == 10) + { + session = scp_session_create(); + + if (0 == session) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + scp_session_set_version(session, version); + + if (code == 0) + { + scp_session_set_type(session, SCP_SESSION_TYPE_XVNC); + } + else + { + scp_session_set_type(session, SCP_SESSION_TYPE_XRDP); + } + + /* reading username */ + in_uint16_be(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); + + if (0 != scp_session_set_username(session, buf)) + { + scp_session_destroy(session); + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* reading password */ + in_uint16_be(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); + + if (0 != scp_session_set_password(session, buf)) + { + scp_session_destroy(session); + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* width */ + in_uint16_be(c->in_s, sz); + scp_session_set_width(session, sz); + /* height */ + in_uint16_be(c->in_s, sz); + scp_session_set_height(session, sz); + /* bpp */ + in_uint16_be(c->in_s, sz); + scp_session_set_bpp(session, (tui8)sz); + + if (s_check_rem(c->in_s, 2)) + { + /* reading domain */ + in_uint16_be(c->in_s, sz); + + if (sz > 0) + { + in_uint8a(c->in_s, buf, sz); + buf[sz] = '\0'; + scp_session_set_domain(session, buf); + } + } + + if (s_check_rem(c->in_s, 2)) + { + /* reading program */ + in_uint16_be(c->in_s, sz); + + if (sz > 0) + { + in_uint8a(c->in_s, buf, sz); + buf[sz] = '\0'; + scp_session_set_program(session, buf); + } + } + + if (s_check_rem(c->in_s, 2)) + { + /* reading directory */ + in_uint16_be(c->in_s, sz); + + if (sz > 0) + { + in_uint8a(c->in_s, buf, sz); + buf[sz] = '\0'; + scp_session_set_directory(session, buf); + } + } + + if (s_check_rem(c->in_s, 2)) + { + /* reading client IP address */ + in_uint16_be(c->in_s, sz); + + if (sz > 0) + { + in_uint8a(c->in_s, buf, sz); + buf[sz] = '\0'; + scp_session_set_client_ip(session, buf); + } + } + } + else if (code == SCP_GW_AUTHENTICATION) + { + /* g_writeln("Command is SCP_GW_AUTHENTICATION"); */ + session = scp_session_create(); + + if (0 == session) + { + /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);*/ + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + scp_session_set_version(session, version); + scp_session_set_type(session, SCP_GW_AUTHENTICATION); + /* reading username */ + in_uint16_be(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); + + /* g_writeln("Received user name: %s",buf); */ + if (0 != scp_session_set_username(session, buf)) + { + scp_session_destroy(session); + /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);*/ + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* reading password */ + in_uint16_be(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); + + /* g_writeln("Received password: %s",buf); */ + if (0 != scp_session_set_password(session, buf)) + { + scp_session_destroy(session); + /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); */ + return SCP_SERVER_STATE_INTERNAL_ERR; + } } else { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - } - - in_uint32_be(c->in_s, size); - - init_stream(c->in_s, 8196); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - c->in_s->end = c->in_s->data + (size - 8); - - in_uint16_be(c->in_s, code); - - if (code == 0 || code == 10) - { - session = scp_session_create(); - if (0 == session) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; } - scp_session_set_version(session, version); - if (code == 0) - { - scp_session_set_type(session, SCP_SESSION_TYPE_XVNC); - } - else - { - scp_session_set_type(session, SCP_SESSION_TYPE_XRDP); - } - - /* reading username */ - in_uint16_be(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_username(session, buf)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - /* reading password */ - in_uint16_be(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_password(session, buf)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - /* width */ - in_uint16_be(c->in_s, sz); - scp_session_set_width(session, sz); - /* height */ - in_uint16_be(c->in_s, sz); - scp_session_set_height(session, sz); - /* bpp */ - in_uint16_be(c->in_s, sz); - scp_session_set_bpp(session, (tui8)sz); - if (s_check_rem(c->in_s, 2)) - { - /* reading domain */ - in_uint16_be(c->in_s, sz); - if (sz > 0) - { - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; - scp_session_set_domain(session, buf); - } - } - if (s_check_rem(c->in_s, 2)) - { - /* reading program */ - in_uint16_be(c->in_s, sz); - if (sz > 0) - { - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; - scp_session_set_program(session, buf); - } - } - if (s_check_rem(c->in_s, 2)) - { - /* reading directory */ - in_uint16_be(c->in_s, sz); - if (sz > 0) - { - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; - scp_session_set_directory(session, buf); - } - } - if (s_check_rem(c->in_s, 2)) - { - /* reading client IP address */ - in_uint16_be(c->in_s, sz); - if (sz > 0) - { - in_uint8a(c->in_s, buf, sz); - buf[sz] = '\0'; - scp_session_set_client_ip(session, buf); - } - } - } - else if (code == SCP_GW_AUTHENTICATION) - { - /* g_writeln("Command is SCP_GW_AUTHENTICATION"); */ - session = scp_session_create(); - if (0 == session) - { - /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);*/ - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - scp_session_set_version(session, version); - scp_session_set_type(session, SCP_GW_AUTHENTICATION); - /* reading username */ - in_uint16_be(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - /* g_writeln("Received user name: %s",buf); */ - if (0 != scp_session_set_username(session, buf)) - { - scp_session_destroy(session); - /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);*/ - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - /* reading password */ - in_uint16_be(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); - /* g_writeln("Received password: %s",buf); */ - if (0 != scp_session_set_password(session, buf)) - { - scp_session_destroy(session); - /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); */ - return SCP_SERVER_STATE_INTERNAL_ERR; - } - } - else - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - (*s)=session; - return SCP_SERVER_STATE_OK; + (*s) = session; + return SCP_SERVER_STATE_OK; } /******************************************************************************/ enum SCP_SERVER_STATES_E -scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d) +scp_v0s_allow_connection(struct SCP_CONNECTION *c, SCP_DISPLAY d) { - out_uint32_be(c->out_s, 0); /* version */ - out_uint32_be(c->out_s, 14); /* size */ - out_uint16_be(c->out_s, 3); /* cmd */ - out_uint16_be(c->out_s, 1); /* data */ - out_uint16_be(c->out_s, d); /* data */ - s_mark_end(c->out_s); + out_uint32_be(c->out_s, 0); /* version */ + out_uint32_be(c->out_s, 14); /* size */ + out_uint16_be(c->out_s, 3); /* cmd */ + out_uint16_be(c->out_s, 1); /* data */ + out_uint16_be(c->out_s, d); /* data */ + s_mark_end(c->out_s); - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } - LOG_DBG("[v0:%d] connection terminated (allowed)", __LINE__); - return SCP_SERVER_STATE_OK; + LOG_DBG("[v0:%d] connection terminated (allowed)", __LINE__); + return SCP_SERVER_STATE_OK; } /******************************************************************************/ enum SCP_SERVER_STATES_E -scp_v0s_deny_connection(struct SCP_CONNECTION* c) +scp_v0s_deny_connection(struct SCP_CONNECTION *c) { - out_uint32_be(c->out_s, 0); /* version */ - out_uint32_be(c->out_s, 14); /* size */ - out_uint16_be(c->out_s, 3); /* cmd */ - out_uint16_be(c->out_s, 0); /* data = 0 - means NOT ok*/ - out_uint16_be(c->out_s, 0); /* reserved for display number*/ - s_mark_end(c->out_s); + out_uint32_be(c->out_s, 0); /* version */ + out_uint32_be(c->out_s, 14); /* size */ + out_uint16_be(c->out_s, 3); /* cmd */ + out_uint16_be(c->out_s, 0); /* data = 0 - means NOT ok*/ + out_uint16_be(c->out_s, 0); /* reserved for display number*/ + s_mark_end(c->out_s); - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) - { - log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) + { + log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } - LOG_DBG("[v0:%d] connection terminated (denied)", __LINE__); - return SCP_SERVER_STATE_OK; + LOG_DBG("[v0:%d] connection terminated (denied)", __LINE__); + return SCP_SERVER_STATE_OK; } /******************************************************************************/ enum SCP_SERVER_STATES_E -scp_v0s_replyauthentication(struct SCP_CONNECTION* c, unsigned short int value) +scp_v0s_replyauthentication(struct SCP_CONNECTION *c, unsigned short int value) { - out_uint32_be(c->out_s, 0); /* version */ - out_uint32_be(c->out_s, 14); /* size */ - /* cmd SCP_GW_AUTHENTICATION means authentication reply */ - out_uint16_be(c->out_s, SCP_GW_AUTHENTICATION); - out_uint16_be(c->out_s, value); /* reply code */ - out_uint16_be(c->out_s, 0); /* dummy data */ - s_mark_end(c->out_s); + out_uint32_be(c->out_s, 0); /* version */ + out_uint32_be(c->out_s, 14); /* size */ + /* cmd SCP_GW_AUTHENTICATION means authentication reply */ + out_uint16_be(c->out_s, SCP_GW_AUTHENTICATION); + out_uint16_be(c->out_s, value); /* reply code */ + out_uint16_be(c->out_s, 0); /* dummy data */ + s_mark_end(c->out_s); - /* g_writeln("Total number of bytes that will be sent %d",c->out_s->end - c->out_s->data);*/ - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) - { - /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); */ - return SCP_SERVER_STATE_NETWORK_ERR; - } + /* g_writeln("Total number of bytes that will be sent %d",c->out_s->end - c->out_s->data);*/ + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data)) + { + /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); */ + return SCP_SERVER_STATE_NETWORK_ERR; + } - /* until syslog merge LOG_DBG(s_log, "[v0:%d] connection terminated (scp_v0s_deny_authentication)", __LINE__);*/ - return SCP_SERVER_STATE_OK; + /* until syslog merge LOG_DBG(s_log, "[v0:%d] connection terminated (scp_v0s_deny_authentication)", __LINE__);*/ + return SCP_SERVER_STATE_OK; } diff --git a/sesman/libscp/libscp_v0.h b/sesman/libscp/libscp_v0.h index 92b835f0..16e49e05 100644 --- a/sesman/libscp/libscp_v0.h +++ b/sesman/libscp/libscp_v0.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -39,7 +38,7 @@ * @param d display * */ -enum SCP_CLIENT_STATES_E +enum SCP_CLIENT_STATES_E scp_v0c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s); /* server API */ @@ -52,7 +51,7 @@ scp_v0c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s); * scp_vXs_accept() ) * */ -enum SCP_SERVER_STATES_E +enum SCP_SERVER_STATES_E scp_v0s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk); /** @@ -61,7 +60,7 @@ scp_v0s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk); * @param c connection descriptor * */ -enum SCP_SERVER_STATES_E +enum SCP_SERVER_STATES_E scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d); /** @@ -70,17 +69,16 @@ scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d); * @param c connection descriptor * */ -enum SCP_SERVER_STATES_E +enum SCP_SERVER_STATES_E scp_v0s_deny_connection(struct SCP_CONNECTION* c); /** * @brief send reply to an authentication request * @param c connection descriptor * @param value the reply code 0 means ok - * @return + * @return */ enum SCP_SERVER_STATES_E scp_v0s_replyauthentication(struct SCP_CONNECTION* c, unsigned short int value); #endif - diff --git a/sesman/libscp/libscp_v1c.c b/sesman/libscp/libscp_v1c.c index 6e1c3b8a..7d1b9db8 100644 --- a/sesman/libscp/libscp_v1c.c +++ b/sesman/libscp/libscp_v1c.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -31,443 +30,477 @@ #include static enum SCP_CLIENT_STATES_E -_scp_v1c_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s); +_scp_v1c_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s); /* client API */ /* 001 */ enum SCP_CLIENT_STATES_E -scp_v1c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +scp_v1c_connect(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - tui8 sz; - tui32 size; + tui8 sz; + tui32 size; - init_stream(c->out_s, c->out_s->size); - init_stream(c->in_s, c->in_s->size); + init_stream(c->out_s, c->out_s->size); + init_stream(c->in_s, c->in_s->size); - size = 19 + 17 + 4 + g_strlen(s->hostname) + g_strlen(s->username) + - g_strlen(s->password); - if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) - { - size = size + 4; - } - else - { - size = size + 16; - } + size = 19 + 17 + 4 + g_strlen(s->hostname) + g_strlen(s->username) + + g_strlen(s->password); - /* sending request */ + if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) + { + size = size + 4; + } + else + { + size = size + 16; + } - /* header */ - out_uint32_be(c->out_s, 1); /* version */ - out_uint32_be(c->out_s, size); - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); - out_uint16_be(c->out_s, 1); + /* sending request */ - /* body */ - out_uint8(c->out_s, s->type); - out_uint16_be(c->out_s, s->height); - out_uint16_be(c->out_s, s->width); - out_uint8(c->out_s, s->bpp); - out_uint8(c->out_s, s->rsr); - out_uint8p(c->out_s, s->locale, 17); - out_uint8(c->out_s, s->addr_type); + /* header */ + out_uint32_be(c->out_s, 1); /* version */ + out_uint32_be(c->out_s, size); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, 1); - if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) - { - out_uint32_be(c->out_s, s->ipv4addr); - } - else if (s->addr_type == SCP_ADDRESS_TYPE_IPV6) - { - out_uint8p(c->out_s, s->ipv6addr, 16); - } + /* body */ + out_uint8(c->out_s, s->type); + out_uint16_be(c->out_s, s->height); + out_uint16_be(c->out_s, s->width); + out_uint8(c->out_s, s->bpp); + out_uint8(c->out_s, s->rsr); + out_uint8p(c->out_s, s->locale, 17); + out_uint8(c->out_s, s->addr_type); - sz = g_strlen(s->hostname); - out_uint8(c->out_s, sz); - out_uint8p(c->out_s, s->hostname, sz); - sz = g_strlen(s->username); - out_uint8(c->out_s, sz); - out_uint8p(c->out_s, s->username, sz); - sz = g_strlen(s->password); - out_uint8(c->out_s, sz); - out_uint8p(c->out_s, s->password, sz); + if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) + { + out_uint32_be(c->out_s, s->ipv4addr); + } + else if (s->addr_type == SCP_ADDRESS_TYPE_IPV6) + { + out_uint8p(c->out_s, s->ipv6addr, 16); + } - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } + sz = g_strlen(s->hostname); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->hostname, sz); + sz = g_strlen(s->username); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->username, sz); + sz = g_strlen(s->password); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->password, sz); - /* wait for response */ - return _scp_v1c_check_response(c, s); + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + /* wait for response */ + return _scp_v1c_check_response(c, s); } /* 004 */ enum SCP_CLIENT_STATES_E -scp_v1c_resend_credentials(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +scp_v1c_resend_credentials(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - tui8 sz; - tui32 size; + tui8 sz; + tui32 size; - init_stream(c->out_s, c->out_s->size); - init_stream(c->in_s, c->in_s->size); + init_stream(c->out_s, c->out_s->size); + init_stream(c->in_s, c->in_s->size); - size = 12 + 2 + g_strlen(s->username) + g_strlen(s->password); + size = 12 + 2 + g_strlen(s->username) + g_strlen(s->password); - /* sending request */ - /* header */ - out_uint32_be(c->out_s, 1); /* version */ - out_uint32_be(c->out_s, size); - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); - out_uint16_be(c->out_s, 4); + /* sending request */ + /* header */ + out_uint32_be(c->out_s, 1); /* version */ + out_uint32_be(c->out_s, size); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, 4); - /* body */ - sz = g_strlen(s->username); - out_uint8(c->out_s, sz); - out_uint8p(c->out_s, s->username, sz); - sz = g_strlen(s->password); - out_uint8(c->out_s, sz); - out_uint8p(c->out_s, s->password, sz); + /* body */ + sz = g_strlen(s->username); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->username, sz); + sz = g_strlen(s->password); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->password, sz); - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } - /* wait for response */ - return _scp_v1c_check_response(c, s); + /* wait for response */ + return _scp_v1c_check_response(c, s); } /* 021 */ enum SCP_CLIENT_STATES_E -scp_v1c_pwd_change(struct SCP_CONNECTION* c, char* newpass); +scp_v1c_pwd_change(struct SCP_CONNECTION *c, char *newpass); /* 022 */ enum SCP_CLIENT_STATES_E -scp_v1c_pwd_change_cancel(struct SCP_CONNECTION* c); +scp_v1c_pwd_change_cancel(struct SCP_CONNECTION *c); /* 041 */ enum SCP_CLIENT_STATES_E -scp_v1c_get_session_list(struct SCP_CONNECTION* c, int* scount, - struct SCP_DISCONNECTED_SESSION** s) +scp_v1c_get_session_list(struct SCP_CONNECTION *c, int *scount, + struct SCP_DISCONNECTED_SESSION **s) { - tui32 version = 1; - tui32 size = 12; - tui16 cmd = 41; - tui32 sescnt = 0; /* total session number */ - tui32 sestmp = 0; /* additional total session number */ - tui8 pktcnt = 0; /* packet session count */ - tui32 totalcnt = 0; /* session counter */ - tui8 continued = 0; /* continue flag */ - int firstpkt = 1; /* "first packet" flag */ - int idx; - struct SCP_DISCONNECTED_SESSION* ds = 0; + tui32 version = 1; + tui32 size = 12; + tui16 cmd = 41; + tui32 sescnt = 0; /* total session number */ + tui32 sestmp = 0; /* additional total session number */ + tui8 pktcnt = 0; /* packet session count */ + tui32 totalcnt = 0; /* session counter */ + tui8 continued = 0; /* continue flag */ + int firstpkt = 1; /* "first packet" flag */ + int idx; + struct SCP_DISCONNECTED_SESSION *ds = 0; - init_stream(c->out_s, c->out_s->size); + init_stream(c->out_s, c->out_s->size); - /* we request session list */ - out_uint32_be(c->out_s, version); /* version */ - out_uint32_be(c->out_s, size); /* size */ - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ - out_uint16_be(c->out_s, cmd); /* cmd */ + /* we request session list */ + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, size); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } - - do - { - /* then we wait for server response */ - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { - return SCP_CLIENT_STATE_NETWORK_ERR; + return SCP_CLIENT_STATE_NETWORK_ERR; } - in_uint32_be(c->in_s, version); - if (version != 1) + do { - return SCP_CLIENT_STATE_VERSION_ERR; + /* then we wait for server response */ + init_stream(c->in_s, c->in_s->size); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint32_be(c->in_s, version); + + if (version != 1) + { + return SCP_CLIENT_STATE_VERSION_ERR; + } + + in_uint32_be(c->in_s, size); + + if (size < 12) + { + return SCP_CLIENT_STATE_SIZE_ERR; + } + + init_stream(c->in_s, c->in_s->size); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_COMMAND_SET_DEFAULT) + { + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != 42) + { + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + if (firstpkt) + { + firstpkt = 0; + in_uint32_be(c->in_s, sescnt); + sestmp = sescnt; + + ds = g_malloc(sizeof(struct SCP_DISCONNECTED_SESSION) * sescnt, 0); + + if (ds == 0) + { + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + } + else + { + in_uint32_be(c->in_s, sestmp); + } + + in_uint8(c->in_s, continued); + in_uint8(c->in_s, pktcnt); + + for (idx = 0; idx < pktcnt; idx++) + { + in_uint32_be(c->in_s, (ds[totalcnt]).SID); /* session id */ + in_uint8(c->in_s, (ds[totalcnt]).type); + in_uint16_be(c->in_s, (ds[totalcnt]).height); + in_uint16_be(c->in_s, (ds[totalcnt]).width); + in_uint8(c->in_s, (ds[totalcnt]).bpp); + in_uint8(c->in_s, (ds[totalcnt]).idle_days); + in_uint8(c->in_s, (ds[totalcnt]).idle_hours); + in_uint8(c->in_s, (ds[totalcnt]).idle_minutes); + + in_uint16_be(c->in_s, (ds[totalcnt]).conn_year); + in_uint8(c->in_s, (ds[totalcnt]).conn_month); + in_uint8(c->in_s, (ds[totalcnt]).conn_day); + in_uint8(c->in_s, (ds[totalcnt]).conn_hour); + in_uint8(c->in_s, (ds[totalcnt]).conn_minute); + in_uint8(c->in_s, (ds[totalcnt]).addr_type); + + if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV4) + { + in_uint32_be(c->in_s, (ds[totalcnt]).ipv4addr); + } + else if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV6) + { + in_uint8a(c->in_s, (ds[totalcnt]).ipv6addr, 16); + } + + totalcnt++; + } } + while (continued); - in_uint32_be(c->in_s, size); - if (size < 12) - { - return SCP_CLIENT_STATE_SIZE_ERR; - } + printf("fine\n"); + /* return data... */ + (*scount) = sescnt; + (*s) = ds; - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_COMMAND_SET_DEFAULT) - { - return SCP_CLIENT_STATE_SEQUENCE_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd != 42) - { - return SCP_CLIENT_STATE_SEQUENCE_ERR; - } - - if (firstpkt) - { - firstpkt = 0; - in_uint32_be(c->in_s, sescnt); - sestmp = sescnt; - - ds = g_malloc(sizeof(struct SCP_DISCONNECTED_SESSION) * sescnt, 0); - if (ds == 0) - { - return SCP_CLIENT_STATE_INTERNAL_ERR; - } - } - else - { - in_uint32_be(c->in_s, sestmp); - } - in_uint8(c->in_s, continued); - in_uint8(c->in_s, pktcnt); - - for (idx = 0; idx < pktcnt; idx++) - { - in_uint32_be(c->in_s, (ds[totalcnt]).SID); /* session id */ - in_uint8(c->in_s, (ds[totalcnt]).type); - in_uint16_be(c->in_s, (ds[totalcnt]).height); - in_uint16_be(c->in_s, (ds[totalcnt]).width); - in_uint8(c->in_s, (ds[totalcnt]).bpp); - in_uint8(c->in_s, (ds[totalcnt]).idle_days); - in_uint8(c->in_s, (ds[totalcnt]).idle_hours); - in_uint8(c->in_s, (ds[totalcnt]).idle_minutes); - - in_uint16_be(c->in_s, (ds[totalcnt]).conn_year); - in_uint8(c->in_s, (ds[totalcnt]).conn_month); - in_uint8(c->in_s, (ds[totalcnt]).conn_day); - in_uint8(c->in_s, (ds[totalcnt]).conn_hour); - in_uint8(c->in_s, (ds[totalcnt]).conn_minute); - in_uint8(c->in_s, (ds[totalcnt]).addr_type); - if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV4) - { - in_uint32_be(c->in_s, (ds[totalcnt]).ipv4addr); - } - else if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV6) - { - in_uint8a(c->in_s, (ds[totalcnt]).ipv6addr, 16); - } - totalcnt++; - } - } - while (continued); - - printf("fine\n"); - /* return data... */ - (*scount) = sescnt; - (*s) = ds; - - return SCP_CLIENT_STATE_LIST_OK; + return SCP_CLIENT_STATE_LIST_OK; } /* 043 */ enum SCP_CLIENT_STATES_E -scp_v1c_select_session(struct SCP_CONNECTION* c, struct SCP_SESSION* s, +scp_v1c_select_session(struct SCP_CONNECTION *c, struct SCP_SESSION *s, SCP_SID sid) { - tui32 version = 1; - tui32 size = 16; - tui16 cmd = 43; + tui32 version = 1; + tui32 size = 16; + tui16 cmd = 43; - init_stream(c->out_s, c->out_s->size); + init_stream(c->out_s, c->out_s->size); - /* sending our selection */ - out_uint32_be(c->out_s, version); /* version */ - out_uint32_be(c->out_s, size); /* size */ - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ - out_uint16_be(c->out_s, cmd); /* cmd */ + /* sending our selection */ + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, size); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ - out_uint32_be(c->out_s, sid); + out_uint32_be(c->out_s, sid); - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } - /* waiting for response.... */ - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } + /* waiting for response.... */ + init_stream(c->in_s, c->in_s->size); - in_uint32_be(c->in_s, version); - if (version != 1) - { - return SCP_CLIENT_STATE_VERSION_ERR; - } + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } - in_uint32_be(c->in_s, size); - if (size < 12) - { - return SCP_CLIENT_STATE_SIZE_ERR; - } + in_uint32_be(c->in_s, version); - init_stream(c->in_s, c->in_s->size); - /* read the rest of the packet */ - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (version != 1) + { + return SCP_CLIENT_STATE_VERSION_ERR; + } - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_COMMAND_SET_DEFAULT) - { - return SCP_CLIENT_STATE_SEQUENCE_ERR; - } + in_uint32_be(c->in_s, size); - in_uint16_be(c->in_s, cmd); - if (cmd != 46) - { - return SCP_CLIENT_STATE_SEQUENCE_ERR; - } + if (size < 12) + { + return SCP_CLIENT_STATE_SIZE_ERR; + } - /* session display */ - in_uint16_be(c->in_s, (s->display)); - /*we don't need to return any data other than the display */ - /*because we already sent that */ + init_stream(c->in_s, c->in_s->size); - return SCP_CLIENT_STATE_OK; + /* read the rest of the packet */ + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_COMMAND_SET_DEFAULT) + { + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != 46) + { + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + /* session display */ + in_uint16_be(c->in_s, (s->display)); + /*we don't need to return any data other than the display */ + /*because we already sent that */ + + return SCP_CLIENT_STATE_OK; } /* 044 */ enum SCP_CLIENT_STATES_E -scp_v1c_select_session_cancel(struct SCP_CONNECTION* c) +scp_v1c_select_session_cancel(struct SCP_CONNECTION *c) { - tui32 version = 1; - tui32 size = 12; - tui16 cmd = 44; + tui32 version = 1; + tui32 size = 12; + tui16 cmd = 44; - init_stream(c->out_s, c->out_s->size); + init_stream(c->out_s, c->out_s->size); - /* sending our selection */ - out_uint32_be(c->out_s, version); /* version */ - out_uint32_be(c->out_s, size); /* size */ - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ - out_uint16_be(c->out_s, cmd); /* cmd */ + /* sending our selection */ + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, size); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } - return SCP_CLIENT_STATE_END; + return SCP_CLIENT_STATE_END; } static enum SCP_CLIENT_STATES_E -_scp_v1c_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +_scp_v1c_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - tui32 version; - tui32 size; - tui16 cmd; - tui16 dim; + tui32 version; + tui32 size; + tui16 cmd; + tui16 dim; - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } + init_stream(c->in_s, c->in_s->size); - in_uint32_be(c->in_s, version); - if (version != 1) - { - return SCP_CLIENT_STATE_VERSION_ERR; - } + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } - in_uint32_be(c->in_s, size); + in_uint32_be(c->in_s, version); - init_stream(c->in_s, c->in_s->size); - /* read the rest of the packet */ - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) - { - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (version != 1) + { + return SCP_CLIENT_STATE_VERSION_ERR; + } + + in_uint32_be(c->in_s, size); + + init_stream(c->in_s, c->in_s->size); + + /* read the rest of the packet */ + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_COMMAND_SET_DEFAULT) + { + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd == 2) /* connection denied */ + { + in_uint16_be(c->in_s, dim); + + if (s->errstr != 0) + { + g_free(s->errstr); + } + + s->errstr = g_malloc(dim + 1, 0); + + if (s->errstr == 0) + { + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + + in_uint8a(c->in_s, s->errstr, dim); + (s->errstr)[dim] = '\0'; + + return SCP_CLIENT_STATE_CONNECTION_DENIED; + } + else if (cmd == 3) /* resend usr/pwd */ + { + in_uint16_be(c->in_s, dim); + + if (s->errstr != 0) + { + g_free(s->errstr); + } + + s->errstr = g_malloc(dim + 1, 0); + + if (s->errstr == 0) + { + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + + in_uint8a(c->in_s, s->errstr, dim); + (s->errstr)[dim] = '\0'; + + return SCP_CLIENT_STATE_RESEND_CREDENTIALS; + } + else if (cmd == 20) /* password change */ + { + in_uint16_be(c->in_s, dim); + + if (s->errstr != 0) + { + g_free(s->errstr); + } + + s->errstr = g_malloc(dim + 1, 0); + + if (s->errstr == 0) + { + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + + in_uint8a(c->in_s, s->errstr, dim); + (s->errstr)[dim] = '\0'; + + return SCP_CLIENT_STATE_PWD_CHANGE_REQ; + } + else if (cmd == 30) /* display */ + { + in_uint16_be(c->in_s, s->display); + + return SCP_CLIENT_STATE_OK; + } + //else if (cmd == 31) /* there's a disconnected session */ + //{ + // return SCP_CLIENT_STATE_RECONNECT_SINGLE; + //} + //else if (cmd == 33) /* display of a disconnected session */ + //{ + // return SCP_CLIENT_STATE_RECONNECT; + //} + else if (cmd == 40) /* session list */ + { + return SCP_CLIENT_STATE_SESSION_LIST; + } - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_COMMAND_SET_DEFAULT) - { return SCP_CLIENT_STATE_SEQUENCE_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd == 2) /* connection denied */ - { - in_uint16_be(c->in_s, dim); - if (s->errstr != 0) - { - g_free(s->errstr); - } - s->errstr = g_malloc(dim + 1, 0); - if (s->errstr == 0) - { - return SCP_CLIENT_STATE_INTERNAL_ERR; - } - in_uint8a(c->in_s, s->errstr, dim); - (s->errstr)[dim] = '\0'; - - return SCP_CLIENT_STATE_CONNECTION_DENIED; - } - else if (cmd == 3) /* resend usr/pwd */ - { - in_uint16_be(c->in_s, dim); - if (s->errstr != 0) - { - g_free(s->errstr); - } - s->errstr = g_malloc(dim + 1, 0); - if (s->errstr == 0) - { - return SCP_CLIENT_STATE_INTERNAL_ERR; - } - in_uint8a(c->in_s, s->errstr, dim); - (s->errstr)[dim] = '\0'; - - return SCP_CLIENT_STATE_RESEND_CREDENTIALS; - } - else if (cmd == 20) /* password change */ - { - in_uint16_be(c->in_s, dim); - if (s->errstr != 0) - { - g_free(s->errstr); - } - s->errstr = g_malloc(dim + 1, 0); - if (s->errstr == 0) - { - return SCP_CLIENT_STATE_INTERNAL_ERR; - } - in_uint8a(c->in_s, s->errstr, dim); - (s->errstr)[dim] = '\0'; - - return SCP_CLIENT_STATE_PWD_CHANGE_REQ; - } - else if (cmd == 30) /* display */ - { - in_uint16_be(c->in_s, s->display); - - return SCP_CLIENT_STATE_OK; - } - //else if (cmd == 31) /* there's a disconnected session */ - //{ - // return SCP_CLIENT_STATE_RECONNECT_SINGLE; - //} - //else if (cmd == 33) /* display of a disconnected session */ - //{ - // return SCP_CLIENT_STATE_RECONNECT; - //} - else if (cmd == 40) /* session list */ - { - return SCP_CLIENT_STATE_SESSION_LIST; - } - - return SCP_CLIENT_STATE_SEQUENCE_ERR; } diff --git a/sesman/libscp/libscp_v1c.h b/sesman/libscp/libscp_v1c.h index f6fd4492..ef5a06cb 100644 --- a/sesman/libscp/libscp_v1c.h +++ b/sesman/libscp/libscp_v1c.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_v1c_mng.c b/sesman/libscp/libscp_v1c_mng.c index 88f86f4f..59762e36 100644 --- a/sesman/libscp/libscp_v1c_mng.c +++ b/sesman/libscp/libscp_v1c_mng.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -33,215 +32,228 @@ //extern struct log_config* s_log; static enum SCP_CLIENT_STATES_E -_scp_v1c_mng_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s); +_scp_v1c_mng_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s); /* client API */ /* 001 */ enum SCP_CLIENT_STATES_E -scp_v1c_mng_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +scp_v1c_mng_connect(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - tui8 sz; - tui32 size; + tui8 sz; + tui32 size; - init_stream(c->out_s, c->out_s->size); - init_stream(c->in_s, c->in_s->size); + init_stream(c->out_s, c->out_s->size); + init_stream(c->in_s, c->in_s->size); - size = 12 + 4 + g_strlen(s->hostname) + g_strlen(s->username) + - g_strlen(s->password); - if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) - { - size = size + 4; - } - else - { - size = size + 16; - } + size = 12 + 4 + g_strlen(s->hostname) + g_strlen(s->username) + + g_strlen(s->password); - /* sending request */ + if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) + { + size = size + 4; + } + else + { + size = size + 16; + } - /* header */ - out_uint32_be(c->out_s, 1); /* version */ - out_uint32_be(c->out_s, size); - out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); - out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN); + /* sending request */ - /* data */ - sz = g_strlen(s->username); - out_uint8(c->out_s, sz); - out_uint8p(c->out_s, s->username, sz); - sz = g_strlen(s->password); - out_uint8(c->out_s, sz); - out_uint8p(c->out_s, s->password, sz); + /* header */ + out_uint32_be(c->out_s, 1); /* version */ + out_uint32_be(c->out_s, size); + out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); + out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN); - /* address */ - out_uint8(c->out_s, s->addr_type); - if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) - { - out_uint32_be(c->out_s, s->ipv4addr); - } - else - { - out_uint8p(c->out_s, s->ipv6addr, 16); - } + /* data */ + sz = g_strlen(s->username); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->username, sz); + sz = g_strlen(s->password); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->password, sz); - /* hostname */ - sz = g_strlen(s->hostname); - out_uint8(c->out_s, sz); - out_uint8p(c->out_s, s->hostname, sz); + /* address */ + out_uint8(c->out_s, s->addr_type); - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (s->addr_type == SCP_ADDRESS_TYPE_IPV4) + { + out_uint32_be(c->out_s, s->ipv4addr); + } + else + { + out_uint8p(c->out_s, s->ipv6addr, 16); + } - /* wait for response */ - return _scp_v1c_mng_check_response(c, s); + /* hostname */ + sz = g_strlen(s->hostname); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->hostname, sz); + + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + /* wait for response */ + return _scp_v1c_mng_check_response(c, s); } /* 004 */ enum SCP_CLIENT_STATES_E -scp_v1c_mng_get_session_list(struct SCP_CONNECTION* c, int* scount, - struct SCP_DISCONNECTED_SESSION** s) +scp_v1c_mng_get_session_list(struct SCP_CONNECTION *c, int *scount, + struct SCP_DISCONNECTED_SESSION **s) { - tui32 version = 1; - tui32 size = 12; - tui16 cmd = SCP_CMD_MNG_LIST_REQ; /* request session list */ - tui32 sescnt = 0; /* total session number */ - tui32 sestmp = 0; /* additional total session number */ - tui8 pktcnt = 0; /* packet session count */ - tui32 totalcnt = 0; /* session counter */ - tui8 continued = 0; /* continue flag */ - int firstpkt = 1; /* "first packet" flag */ - int idx; - struct SCP_DISCONNECTED_SESSION* ds = 0; -// tui8 addr[16]; + tui32 version = 1; + tui32 size = 12; + tui16 cmd = SCP_CMD_MNG_LIST_REQ; /* request session list */ + tui32 sescnt = 0; /* total session number */ + tui32 sestmp = 0; /* additional total session number */ + tui8 pktcnt = 0; /* packet session count */ + tui32 totalcnt = 0; /* session counter */ + tui8 continued = 0; /* continue flag */ + int firstpkt = 1; /* "first packet" flag */ + int idx; + struct SCP_DISCONNECTED_SESSION *ds = 0; + // tui8 addr[16]; - init_stream(c->out_s, c->out_s->size); + init_stream(c->out_s, c->out_s->size); - /* we request session list */ - out_uint32_be(c->out_s, version); /* version */ - out_uint32_be(c->out_s, size); /* size */ - out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); /* cmdset */ - out_uint16_be(c->out_s, cmd); /* cmd */ + /* we request session list */ + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, size); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; - } - - do - { - /* then we wait for server response */ - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; } - in_uint32_be(c->in_s, version); - if (version != 1) + do { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: version error", __LINE__); - return SCP_CLIENT_STATE_VERSION_ERR; + /* then we wait for server response */ + init_stream(c->in_s, c->in_s->size); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint32_be(c->in_s, version); + + if (version != 1) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: version error", __LINE__); + return SCP_CLIENT_STATE_VERSION_ERR; + } + + in_uint32_be(c->in_s, size); + + if (size < 12) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: size error", __LINE__); + return SCP_CLIENT_STATE_SIZE_ERR; + } + + init_stream(c->in_s, c->in_s->size); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_COMMAND_SET_MANAGE) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_CMD_MNG_LIST) /* session list */ + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + if (firstpkt) + { + firstpkt = 0; + in_uint32_be(c->in_s, sescnt); + sestmp = sescnt; + + if (0 == sescnt) + { + /* return data... */ + (*scount) = sescnt; + (*s) = NULL; + + LOG_DBG("[v1c_mng] end list - no session on TS"); + return SCP_CLIENT_STATE_LIST_OK; + } + + ds = g_malloc(sizeof(struct SCP_DISCONNECTED_SESSION) * sescnt, 0); + + if (ds == 0) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: internal error", __LINE__); + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + } + else + { + in_uint32_be(c->in_s, sestmp); + } + + in_uint8(c->in_s, continued); + in_uint8(c->in_s, pktcnt); + + for (idx = 0; idx < pktcnt; idx++) + { + in_uint32_be(c->in_s, (ds[totalcnt]).SID); /* session id */ + in_uint8(c->in_s, (ds[totalcnt]).type); + in_uint16_be(c->in_s, (ds[totalcnt]).height); + in_uint16_be(c->in_s, (ds[totalcnt]).width); + in_uint8(c->in_s, (ds[totalcnt]).bpp); + in_uint8(c->in_s, (ds[totalcnt]).idle_days); + in_uint8(c->in_s, (ds[totalcnt]).idle_hours); + in_uint8(c->in_s, (ds[totalcnt]).idle_minutes); + + in_uint16_be(c->in_s, (ds[totalcnt]).conn_year); + in_uint8(c->in_s, (ds[totalcnt]).conn_month); + in_uint8(c->in_s, (ds[totalcnt]).conn_day); + in_uint8(c->in_s, (ds[totalcnt]).conn_hour); + in_uint8(c->in_s, (ds[totalcnt]).conn_minute); + in_uint8(c->in_s, (ds[totalcnt]).addr_type); + + if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV4) + { + in_uint32_be(c->in_s, (ds[totalcnt]).ipv4addr); + } + + if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV6) + { + in_uint8a(c->in_s, (ds[totalcnt]).ipv6addr, 16); + } + + totalcnt++; + } } + while (continued); - in_uint32_be(c->in_s, size); - if (size < 12) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: size error", __LINE__); - return SCP_CLIENT_STATE_SIZE_ERR; - } + /* return data... */ + (*scount) = sescnt; + (*s) = ds; - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_COMMAND_SET_MANAGE) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); - return SCP_CLIENT_STATE_SEQUENCE_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_CMD_MNG_LIST) /* session list */ - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); - return SCP_CLIENT_STATE_SEQUENCE_ERR; - } - - if (firstpkt) - { - firstpkt = 0; - in_uint32_be(c->in_s, sescnt); - sestmp = sescnt; - - if (0 == sescnt) - { - /* return data... */ - (*scount) = sescnt; - (*s) = NULL; - - LOG_DBG("[v1c_mng] end list - no session on TS"); - return SCP_CLIENT_STATE_LIST_OK; - } - - ds = g_malloc(sizeof(struct SCP_DISCONNECTED_SESSION) * sescnt, 0); - if (ds == 0) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: internal error", __LINE__); - return SCP_CLIENT_STATE_INTERNAL_ERR; - } - } - else - { - in_uint32_be(c->in_s, sestmp); - } - in_uint8(c->in_s, continued); - in_uint8(c->in_s, pktcnt); - - for (idx = 0; idx < pktcnt; idx++) - { - in_uint32_be(c->in_s, (ds[totalcnt]).SID); /* session id */ - in_uint8(c->in_s, (ds[totalcnt]).type); - in_uint16_be(c->in_s, (ds[totalcnt]).height); - in_uint16_be(c->in_s, (ds[totalcnt]).width); - in_uint8(c->in_s, (ds[totalcnt]).bpp); - in_uint8(c->in_s, (ds[totalcnt]).idle_days); - in_uint8(c->in_s, (ds[totalcnt]).idle_hours); - in_uint8(c->in_s, (ds[totalcnt]).idle_minutes); - - in_uint16_be(c->in_s, (ds[totalcnt]).conn_year); - in_uint8(c->in_s, (ds[totalcnt]).conn_month); - in_uint8(c->in_s, (ds[totalcnt]).conn_day); - in_uint8(c->in_s, (ds[totalcnt]).conn_hour); - in_uint8(c->in_s, (ds[totalcnt]).conn_minute); - in_uint8(c->in_s, (ds[totalcnt]).addr_type); - if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV4) - { - in_uint32_be(c->in_s, (ds[totalcnt]).ipv4addr); - } - if ((ds[totalcnt]).addr_type == SCP_ADDRESS_TYPE_IPV6) - { - in_uint8a(c->in_s, (ds[totalcnt]).ipv6addr, 16); - } - totalcnt++; - } - } - while (continued); - - /* return data... */ - (*scount) = sescnt; - (*s) = ds; - - LOG_DBG("[v1c_mng] end list"); - return SCP_CLIENT_STATE_LIST_OK; + LOG_DBG("[v1c_mng] end list"); + return SCP_CLIENT_STATE_LIST_OK; } /* 043 * / @@ -339,62 +351,67 @@ scp_v1c_select_session_cancel(struct SCP_CONNECTION* c) }*/ static enum SCP_CLIENT_STATES_E -_scp_v1c_mng_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +_scp_v1c_mng_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - tui32 version; - tui32 size; - tui16 cmd; - tui8 dim; - char buf[257]; + tui32 version; + tui32 size; + tui16 cmd; + tui8 dim; + char buf[257]; - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; - } + init_stream(c->in_s, c->in_s->size); - in_uint32_be(c->in_s, version); - if (version != 1) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: version error", __LINE__); - return SCP_CLIENT_STATE_VERSION_ERR; - } + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; + } - in_uint32_be(c->in_s, size); + in_uint32_be(c->in_s, version); - init_stream(c->in_s, c->in_s->size); - /* read the rest of the packet */ - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); - return SCP_CLIENT_STATE_NETWORK_ERR; - } + if (version != 1) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: version error", __LINE__); + return SCP_CLIENT_STATE_VERSION_ERR; + } - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_COMMAND_SET_MANAGE) - { - log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); + in_uint32_be(c->in_s, size); + + init_stream(c->in_s, c->in_s->size); + + /* read the rest of the packet */ + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: network error", __LINE__); + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_COMMAND_SET_MANAGE) + { + log_message(LOG_LEVEL_WARNING, "[v1c_mng:%d] connection aborted: sequence error", __LINE__); + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd == SCP_CMD_MNG_LOGIN_ALLOW) /* connection ok */ + { + log_message(LOG_LEVEL_INFO, "[v1c_mng:%d] connection ok", __LINE__); + return SCP_CLIENT_STATE_OK; + } + else if (cmd == SCP_CMD_MNG_LOGIN_DENY) /* connection denied */ + { + in_uint8(c->in_s, dim); + buf[dim] = '\0'; + in_uint8a(c->in_s, buf, dim); + scp_session_set_errstr(s, buf); + + log_message(LOG_LEVEL_INFO, "[v1c_mng:%d] connection denied: %s", __LINE__ , s->errstr); + return SCP_CLIENT_STATE_CONNECTION_DENIED; + } + + log_message(LOG_LEVEL_WARNING, "[v1c-mng:%d] connection aborted: sequence error", __LINE__); return SCP_CLIENT_STATE_SEQUENCE_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd == SCP_CMD_MNG_LOGIN_ALLOW) /* connection ok */ - { - log_message(LOG_LEVEL_INFO, "[v1c_mng:%d] connection ok", __LINE__); - return SCP_CLIENT_STATE_OK; - } - else if (cmd == SCP_CMD_MNG_LOGIN_DENY) /* connection denied */ - { - in_uint8(c->in_s, dim); - buf[dim]='\0'; - in_uint8a(c->in_s, buf, dim); - scp_session_set_errstr(s, buf); - - log_message(LOG_LEVEL_INFO, "[v1c_mng:%d] connection denied: %s", __LINE__ , s->errstr); - return SCP_CLIENT_STATE_CONNECTION_DENIED; - } - - log_message(LOG_LEVEL_WARNING, "[v1c-mng:%d] connection aborted: sequence error", __LINE__); - return SCP_CLIENT_STATE_SEQUENCE_ERR; } diff --git a/sesman/libscp/libscp_v1c_mng.h b/sesman/libscp/libscp_v1c_mng.h index f030d4bf..126c9113 100644 --- a/sesman/libscp/libscp_v1c_mng.h +++ b/sesman/libscp/libscp_v1c_mng.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_v1s.c b/sesman/libscp/libscp_v1s.c index e10af26c..69997ab2 100644 --- a/sesman/libscp/libscp_v1s.c +++ b/sesman/libscp/libscp_v1s.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -33,634 +32,668 @@ //extern struct log_config* s_log; /* server API */ -enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk) +enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk) { - struct SCP_SESSION* session; - tui32 version; - tui32 size; - tui16 cmdset; - tui16 cmd; - tui8 sz; - char buf[257]; + struct SCP_SESSION *session; + tui32 version; + tui32 size; + tui16 cmdset; + tui16 cmd; + tui8 sz; + char buf[257]; - if (!skipVchk) - { - - if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + if (!skipVchk) + { + + if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + in_uint32_be(c->in_s, version); + + if (version != 1) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); + return SCP_SERVER_STATE_VERSION_ERR; + } + } + else + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + } + + in_uint32_be(c->in_s, size); + + if (size < 12) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + + init_stream(c->in_s, c->in_s->size); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8))) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + /* reading command set */ + in_uint16_be(c->in_s, cmdset); + + /* if we are starting a management session */ + if (cmdset == SCP_COMMAND_SET_MANAGE) + { + log_message(LOG_LEVEL_DEBUG, "[v1s:%d] requested management connection", __LINE__); + /* should return SCP_SERVER_STATE_START_MANAGE */ + return scp_v1s_mng_accept(c, s); + } + + /* if we started with resource sharing... */ + if (cmdset == SCP_COMMAND_SET_RSR) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + /* reading command */ + in_uint16_be(c->in_s, cmd); + + if (cmd != 1) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + session = scp_session_create(); + + if (0 == session) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (malloc returned NULL)", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + scp_session_set_version(session, 1); + + in_uint8(c->in_s, sz); + + if ((sz != SCP_SESSION_TYPE_XVNC) && (sz != SCP_SESSION_TYPE_XRDP)) + { + scp_session_destroy(session); + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__); + return SCP_SERVER_STATE_SESSION_TYPE_ERR; + } + + scp_session_set_type(session, sz); + + in_uint16_be(c->in_s, cmd); + scp_session_set_height(session, cmd); + in_uint16_be(c->in_s, cmd); + scp_session_set_height(session, cmd); + in_uint8(c->in_s, sz); + scp_session_set_bpp(session, sz); + in_uint8(c->in_s, sz); + scp_session_set_rsr(session, sz); + in_uint8a(c->in_s, buf, 17); + buf[17] = '\0'; + scp_session_set_locale(session, buf); + + in_uint8(c->in_s, sz); + + if (sz == SCP_ADDRESS_TYPE_IPV4) + { + in_uint32_be(c->in_s, size); + scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV4_BIN, &size); + } + else if (sz == SCP_ADDRESS_TYPE_IPV6) + { + in_uint8a(c->in_s, buf, 16); + scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV6_BIN, buf); + } + + buf[256] = '\0'; + /* reading hostname */ + in_uint8(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); + + if (0 != scp_session_set_hostname(session, buf)) + { + scp_session_destroy(session); + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* reading username */ + in_uint8(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); + + if (0 != scp_session_set_username(session, buf)) + { + scp_session_destroy(session); + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* reading password */ + in_uint8(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); + + if (0 != scp_session_set_password(session, buf)) + { + scp_session_destroy(session); + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* returning the struct */ + (*s) = session; + + return SCP_SERVER_STATE_OK; +} + +enum SCP_SERVER_STATES_E +scp_v1s_deny_connection(struct SCP_CONNECTION *c, char *reason) +{ + int rlen; + + init_stream(c->out_s, c->out_s->size); + + /* forcing message not to exceed 64k */ + rlen = g_strlen(reason); + + if (rlen > 65535) + { + rlen = 65535; + } + + out_uint32_be(c->out_s, 1); + /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason)*/ + /* version + size + cmdset + cmd + msglen + msg */ + out_uint32_be(c->out_s, rlen + 14); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, 2); + out_uint16_be(c->out_s, rlen); + out_uint8p(c->out_s, reason, rlen); + + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, rlen + 14)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + return SCP_SERVER_STATE_END; +} + +enum SCP_SERVER_STATES_E +scp_v1s_request_password(struct SCP_CONNECTION *c, struct SCP_SESSION *s, char *reason) +{ + tui8 sz; + tui32 version; + tui32 size; + tui16 cmdset; + tui16 cmd; + int rlen; + char buf[257]; + + init_stream(c->in_s, c->in_s->size); + init_stream(c->out_s, c->out_s->size); + + /* forcing message not to exceed 64k */ + rlen = g_strlen(reason); + + if (rlen > 65535) + { + rlen = 65535; + } + + /* send password request */ + version = 1; + cmd = 3; + + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, 14 + rlen); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ + + out_uint16_be(c->out_s, rlen); + out_uint8p(c->out_s, reason, rlen); + + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, 14 + rlen)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + /* receive password & username */ + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + in_uint32_be(c->in_s, version); + + if (version != 1) { - in_uint32_be(c->in_s, version); - if (version != 1) - { log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); return SCP_SERVER_STATE_VERSION_ERR; - } } - else - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - } - in_uint32_be(c->in_s, size); - if (size < 12) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); - return SCP_SERVER_STATE_SIZE_ERR; - } - - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - - /* reading command set */ - in_uint16_be(c->in_s, cmdset); - - /* if we are starting a management session */ - if (cmdset == SCP_COMMAND_SET_MANAGE) - { - log_message(LOG_LEVEL_DEBUG, "[v1s:%d] requested management connection", __LINE__); - /* should return SCP_SERVER_STATE_START_MANAGE */ - return scp_v1s_mng_accept(c, s); - } - - /* if we started with resource sharing... */ - if (cmdset == SCP_COMMAND_SET_RSR) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - /* reading command */ - in_uint16_be(c->in_s, cmd); - if (cmd != 1) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - session = scp_session_create(); - if (0 == session) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (malloc returned NULL)", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - scp_session_set_version(session, 1); - - in_uint8(c->in_s, sz); - if ((sz != SCP_SESSION_TYPE_XVNC) && (sz != SCP_SESSION_TYPE_XRDP)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__); - return SCP_SERVER_STATE_SESSION_TYPE_ERR; - } - scp_session_set_type(session, sz); - - in_uint16_be(c->in_s, cmd); - scp_session_set_height(session, cmd); - in_uint16_be(c->in_s, cmd); - scp_session_set_height(session, cmd); - in_uint8(c->in_s, sz); - scp_session_set_bpp(session, sz); - in_uint8(c->in_s, sz); - scp_session_set_rsr(session, sz); - in_uint8a(c->in_s, buf, 17); - buf[17]='\0'; - scp_session_set_locale(session, buf); - - in_uint8(c->in_s, sz); - if (sz == SCP_ADDRESS_TYPE_IPV4) - { in_uint32_be(c->in_s, size); - scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV4_BIN, &size); - } - else if (sz == SCP_ADDRESS_TYPE_IPV6) - { - in_uint8a(c->in_s, buf, 16); - scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV6_BIN, buf); - } - buf[256] = '\0'; - /* reading hostname */ - in_uint8(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_hostname(session, buf)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } + if (size < 12) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } - /* reading username */ - in_uint8(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_username(session, buf)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } + init_stream(c->in_s, c->in_s->size); - /* reading password */ - in_uint8(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_password(session, buf)) - { - scp_session_destroy(session); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8))) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } - /* returning the struct */ - (*s)=session; + in_uint16_be(c->in_s, cmdset); - return SCP_SERVER_STATE_OK; -} + if (cmdset != SCP_COMMAND_SET_DEFAULT) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } -enum SCP_SERVER_STATES_E -scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* reason) -{ - int rlen; + in_uint16_be(c->in_s, cmd); - init_stream(c->out_s,c->out_s->size); + if (cmd != 4) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } - /* forcing message not to exceed 64k */ - rlen = g_strlen(reason); - if (rlen > 65535) - { - rlen = 65535; - } + buf[256] = '\0'; + /* reading username */ + in_uint8(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); - out_uint32_be(c->out_s, 1); - /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason)*/ - /* version + size + cmdset + cmd + msglen + msg */ - out_uint32_be(c->out_s, rlen+14); - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); - out_uint16_be(c->out_s, 2); - out_uint16_be(c->out_s, rlen); - out_uint8p(c->out_s, reason, rlen); + if (0 != scp_session_set_username(s, buf)) + { + scp_session_destroy(s); + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } - if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, rlen+14)) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } + /* reading password */ + in_uint8(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); - return SCP_SERVER_STATE_END; -} + if (0 != scp_session_set_password(s, buf)) + { + scp_session_destroy(s); + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); + return SCP_SERVER_STATE_INTERNAL_ERR; + } -enum SCP_SERVER_STATES_E -scp_v1s_request_password(struct SCP_CONNECTION* c, struct SCP_SESSION* s, char* reason) -{ - tui8 sz; - tui32 version; - tui32 size; - tui16 cmdset; - tui16 cmd; - int rlen; - char buf[257]; - - init_stream(c->in_s, c->in_s->size); - init_stream(c->out_s, c->out_s->size); - - /* forcing message not to exceed 64k */ - rlen = g_strlen(reason); - if (rlen > 65535) - { - rlen = 65535; - } - - /* send password request */ - version=1; - cmd=3; - - out_uint32_be(c->out_s, version); /* version */ - out_uint32_be(c->out_s, 14+rlen); /* size */ - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ - out_uint16_be(c->out_s, cmd); /* cmd */ - - out_uint16_be(c->out_s, rlen); - out_uint8p(c->out_s, reason, rlen); - - if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, 14+rlen)) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - - /* receive password & username */ - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - - in_uint32_be(c->in_s, version); - if (version!=1) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); - return SCP_SERVER_STATE_VERSION_ERR; - } - - in_uint32_be(c->in_s, size); - if (size<12) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); - return SCP_SERVER_STATE_SIZE_ERR; - } - - init_stream(c->in_s, c->in_s->size); - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - - in_uint16_be(c->in_s, cmdset); - if (cmdset != SCP_COMMAND_SET_DEFAULT) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd != 4) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - buf[256] = '\0'; - /* reading username */ - in_uint8(c->in_s, sz); - buf[sz] = '\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_username(s, buf)) - { - scp_session_destroy(s); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - /* reading password */ - in_uint8(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_password(s, buf)) - { - scp_session_destroy(s); - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__); - return SCP_SERVER_STATE_INTERNAL_ERR; - } - - return SCP_SERVER_STATE_OK; + return SCP_SERVER_STATE_OK; } /* 020 */ enum SCP_SERVER_STATES_E -scp_v1s_request_pwd_change(struct SCP_CONNECTION* c, char* reason, char* npw) +scp_v1s_request_pwd_change(struct SCP_CONNECTION *c, char *reason, char *npw) { - return SCP_SERVER_STATE_INTERNAL_ERR; + return SCP_SERVER_STATE_INTERNAL_ERR; } /* 023 */ enum SCP_SERVER_STATES_E -scp_v1s_pwd_change_error(struct SCP_CONNECTION* c, char* error, int retry, char* npw) +scp_v1s_pwd_change_error(struct SCP_CONNECTION *c, char *error, int retry, char *npw) { - return SCP_SERVER_STATE_INTERNAL_ERR; + return SCP_SERVER_STATE_INTERNAL_ERR; } /* 030 */ enum SCP_SERVER_STATES_E -scp_v1s_connect_new_session(struct SCP_CONNECTION* c, SCP_DISPLAY d) +scp_v1s_connect_new_session(struct SCP_CONNECTION *c, SCP_DISPLAY d) { - /* send password request */ - tui32 version=1; - tui32 size=14; - tui16 cmd=30; + /* send password request */ + tui32 version = 1; + tui32 size = 14; + tui16 cmd = 30; - init_stream(c->out_s, c->out_s->size); + init_stream(c->out_s, c->out_s->size); - out_uint32_be(c->out_s, version); /* version */ - out_uint32_be(c->out_s, size); /* size */ - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ - out_uint16_be(c->out_s, cmd); /* cmd */ + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, size); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ - out_uint16_be(c->out_s, d); /* display */ + out_uint16_be(c->out_s, d); /* display */ - if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, 14)) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, 14)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } - return SCP_SERVER_STATE_OK; + return SCP_SERVER_STATE_OK; } /* 032 */ enum SCP_SERVER_STATES_E -scp_v1s_connection_error(struct SCP_CONNECTION* c, char* error) +scp_v1s_connection_error(struct SCP_CONNECTION *c, char *error) { - tui16 len; + tui16 len; - len = g_strlen(error); - init_stream(c->out_s,c->out_s->size); + len = g_strlen(error); + init_stream(c->out_s, c->out_s->size); - out_uint32_be(c->out_s, 1); - /* packet size: 4 + 4 + 2 + 2 + len */ - /* version + size + cmdset + cmd */ - out_uint32_be(c->out_s, (12 + len)); - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); - out_uint16_be(c->out_s, SCP_CMD_CONN_ERROR); + out_uint32_be(c->out_s, 1); + /* packet size: 4 + 4 + 2 + 2 + len */ + /* version + size + cmdset + cmd */ + out_uint32_be(c->out_s, (12 + len)); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, SCP_CMD_CONN_ERROR); - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, (12 + len))) - { - return SCP_SERVER_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, (12 + len))) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } - return SCP_SERVER_STATE_END; + return SCP_SERVER_STATE_END; } /* 040 */ enum SCP_SERVER_STATES_E -scp_v1s_list_sessions(struct SCP_CONNECTION* c, int sescnt, struct SCP_DISCONNECTED_SESSION* ds, SCP_SID* sid) +scp_v1s_list_sessions(struct SCP_CONNECTION *c, int sescnt, struct SCP_DISCONNECTED_SESSION *ds, SCP_SID *sid) { - tui32 version=1; - tui32 size=12; - tui16 cmd=40; - int pktcnt; - int idx; - int sidx; - int pidx; - struct SCP_DISCONNECTED_SESSION* cds; + tui32 version = 1; + tui32 size = 12; + tui16 cmd = 40; + int pktcnt; + int idx; + int sidx; + int pidx; + struct SCP_DISCONNECTED_SESSION *cds; - /* first we send a notice that we have some disconnected sessions */ - init_stream(c->out_s, c->out_s->size); - - out_uint32_be(c->out_s, version); /* version */ - out_uint32_be(c->out_s, size); /* size */ - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ - out_uint16_be(c->out_s, cmd); /* cmd */ - - if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - - /* then we wait for client ack */ -#warning maybe this message could say if the session should be resized on -#warning server side or client side - init_stream(c->in_s, c->in_s->size); - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - - in_uint32_be(c->in_s, version); - if (version!=1) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); - return SCP_SERVER_STATE_VERSION_ERR; - } - - in_uint32_be(c->in_s, size); - if (size<12) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); - return SCP_SERVER_STATE_SIZE_ERR; - } - - init_stream(c->in_s, c->in_s->size); - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_COMMAND_SET_DEFAULT) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd != 41) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - /* calculating the number of packets to send */ - pktcnt=sescnt/SCP_SERVER_MAX_LIST_SIZE; - if ((sescnt%SCP_SERVER_MAX_LIST_SIZE)!=0) - { - pktcnt++; - } - - for (idx=0; idxout_s, c->out_s->size); - /* size: ver+size+cmdset+cmd+sescnt+continue+count */ - size=4+4+2+2+4+1+1; - - /* header */ - cmd=42; - s_push_layer(c->out_s, channel_hdr, 8); - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); - out_uint16_be(c->out_s, cmd); - - /* session count */ - out_uint32_be(c->out_s, sescnt); - - /* setting the continue flag */ - if ((idx+1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt) - { - out_uint8(c->out_s, 0); - /* setting session count for this packet */ - pidx=sescnt-(idx*SCP_SERVER_MAX_LIST_SIZE); - out_uint8(c->out_s, pidx); - } - else - { - out_uint8(c->out_s, 1); - /* setting session count for this packet */ - pidx=SCP_SERVER_MAX_LIST_SIZE; - out_uint8(c->out_s, pidx); - } - - /* adding session descriptors */ - for (sidx=0; sidxout_s, cds->SID); /* session id */ - out_uint8(c->out_s, cds->type); - out_uint16_be(c->out_s, cds->height); - out_uint16_be(c->out_s, cds->width); - out_uint8(c->out_s, cds->bpp); - out_uint8(c->out_s, cds->idle_days); - out_uint8(c->out_s, cds->idle_hours); - out_uint8(c->out_s, cds->idle_minutes); - size += 13; - - out_uint16_be(c->out_s, cds->conn_year); - out_uint8(c->out_s, cds->conn_month); - out_uint8(c->out_s, cds->conn_day); - out_uint8(c->out_s, cds->conn_hour); - out_uint8(c->out_s, cds->conn_minute); - out_uint8(c->out_s, cds->addr_type); - size += 7; - - if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4) - { - in_uint32_be(c->out_s, cds->ipv4addr); - size += 4; - } - else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6) - { - in_uint8a(c->out_s, cds->ipv6addr, 16); - size += 16; - } - } - - s_pop_layer(c->out_s, channel_hdr); - out_uint32_be(c->out_s, version); - out_uint32_be(c->out_s, size); + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, size); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; } - } - /* we get the response */ - init_stream(c->in_s, c->in_s->size); - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (8))) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } + /* then we wait for client ack */ +#warning maybe this message could say if the session should be resized on +#warning server side or client side + init_stream(c->in_s, c->in_s->size); - in_uint32_be(c->in_s, version); - if (version != 1) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); - return SCP_SERVER_STATE_VERSION_ERR; - } - - in_uint32_be(c->in_s, size); - if (size < 12) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); - return SCP_SERVER_STATE_SIZE_ERR; - } - - /* rest of the packet */ - init_stream(c->in_s, c->in_s->size); - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_COMMAND_SET_DEFAULT) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd == 43) - { - /* select session */ - in_uint32_be(c->in_s, (*sid)); - - /* checking sid value */ - for (idx=0; idxin_sck, c->in_s->data, 8)) { - /* the sid is valid */ - if (ds[idx].SID==(*sid)) - { - /* ok, session selected */ - return SCP_SERVER_STATE_OK; - } + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; } - /* if we got here, the requested sid wasn't one from the list we sent */ - /* we should kill the connection */ - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (no such session in list)", __LINE__); - return SCP_CLIENT_STATE_INTERNAL_ERR; - } - else if (cmd == 44) - { - /* cancel connection */ - return SCP_SERVER_STATE_SELECTION_CANCEL; - } -// else if (cmd == 45) -// { -// /* force new connection */ -// return SCP_SERVER_STATE_FORCE_NEW; -// } - else - { - /* wrong response */ - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; - } + in_uint32_be(c->in_s, version); - return SCP_SERVER_STATE_OK; + if (version != 1) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); + return SCP_SERVER_STATE_VERSION_ERR; + } + + in_uint32_be(c->in_s, size); + + if (size < 12) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + + init_stream(c->in_s, c->in_s->size); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8))) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_COMMAND_SET_DEFAULT) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != 41) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + /* calculating the number of packets to send */ + pktcnt = sescnt / SCP_SERVER_MAX_LIST_SIZE; + + if ((sescnt % SCP_SERVER_MAX_LIST_SIZE) != 0) + { + pktcnt++; + } + + for (idx = 0; idx < pktcnt; idx++) + { + /* ok, we send session session list */ + init_stream(c->out_s, c->out_s->size); + + /* size: ver+size+cmdset+cmd+sescnt+continue+count */ + size = 4 + 4 + 2 + 2 + 4 + 1 + 1; + + /* header */ + cmd = 42; + s_push_layer(c->out_s, channel_hdr, 8); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, cmd); + + /* session count */ + out_uint32_be(c->out_s, sescnt); + + /* setting the continue flag */ + if ((idx + 1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt) + { + out_uint8(c->out_s, 0); + /* setting session count for this packet */ + pidx = sescnt - (idx * SCP_SERVER_MAX_LIST_SIZE); + out_uint8(c->out_s, pidx); + } + else + { + out_uint8(c->out_s, 1); + /* setting session count for this packet */ + pidx = SCP_SERVER_MAX_LIST_SIZE; + out_uint8(c->out_s, pidx); + } + + /* adding session descriptors */ + for (sidx = 0; sidx < pidx; sidx++) + { + /* shortcut to the current session to send */ + cds = ds + ((idx) * SCP_SERVER_MAX_LIST_SIZE) + sidx; + + /* session data */ + out_uint32_be(c->out_s, cds->SID); /* session id */ + out_uint8(c->out_s, cds->type); + out_uint16_be(c->out_s, cds->height); + out_uint16_be(c->out_s, cds->width); + out_uint8(c->out_s, cds->bpp); + out_uint8(c->out_s, cds->idle_days); + out_uint8(c->out_s, cds->idle_hours); + out_uint8(c->out_s, cds->idle_minutes); + size += 13; + + out_uint16_be(c->out_s, cds->conn_year); + out_uint8(c->out_s, cds->conn_month); + out_uint8(c->out_s, cds->conn_day); + out_uint8(c->out_s, cds->conn_hour); + out_uint8(c->out_s, cds->conn_minute); + out_uint8(c->out_s, cds->addr_type); + size += 7; + + if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4) + { + in_uint32_be(c->out_s, cds->ipv4addr); + size += 4; + } + else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6) + { + in_uint8a(c->out_s, cds->ipv6addr, 16); + size += 16; + } + } + + s_pop_layer(c->out_s, channel_hdr); + out_uint32_be(c->out_s, version); + out_uint32_be(c->out_s, size); + + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + } + + /* we get the response */ + init_stream(c->in_s, c->in_s->size); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (8))) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + in_uint32_be(c->in_s, version); + + if (version != 1) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: version error", __LINE__); + return SCP_SERVER_STATE_VERSION_ERR; + } + + in_uint32_be(c->in_s, size); + + if (size < 12) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__); + return SCP_SERVER_STATE_SIZE_ERR; + } + + /* rest of the packet */ + init_stream(c->in_s, c->in_s->size); + + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8))) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_COMMAND_SET_DEFAULT) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd == 43) + { + /* select session */ + in_uint32_be(c->in_s, (*sid)); + + /* checking sid value */ + for (idx = 0; idx < sescnt; idx++) + { + /* the sid is valid */ + if (ds[idx].SID == (*sid)) + { + /* ok, session selected */ + return SCP_SERVER_STATE_OK; + } + } + + /* if we got here, the requested sid wasn't one from the list we sent */ + /* we should kill the connection */ + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (no such session in list)", __LINE__); + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + else if (cmd == 44) + { + /* cancel connection */ + return SCP_SERVER_STATE_SELECTION_CANCEL; + } + // else if (cmd == 45) + // { + // /* force new connection */ + // return SCP_SERVER_STATE_FORCE_NEW; + // } + else + { + /* wrong response */ + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + return SCP_SERVER_STATE_OK; } /* 046 was: 031 struct SCP_DISCONNECTED_SESSION* ds, */ enum SCP_SERVER_STATES_E -scp_v1s_reconnect_session(struct SCP_CONNECTION* c, SCP_DISPLAY d) +scp_v1s_reconnect_session(struct SCP_CONNECTION *c, SCP_DISPLAY d) { - tui32 version = 1; - tui32 size = 14; - tui16 cmd = 46; + tui32 version = 1; + tui32 size = 14; + tui16 cmd = 46; - /* ok, we send session data and display */ - init_stream(c->out_s, c->out_s->size); + /* ok, we send session data and display */ + init_stream(c->out_s, c->out_s->size); - /* header */ - out_uint32_be(c->out_s, version); - out_uint32_be(c->out_s, size); - out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); - out_uint16_be(c->out_s, cmd); + /* header */ + out_uint32_be(c->out_s, version); + out_uint32_be(c->out_s, size); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, cmd); - /* session data */ - out_uint16_be(c->out_s, d); /* session display */ - /*out_uint8(c->out_s, ds->type); - out_uint16_be(c->out_s, ds->height); - out_uint16_be(c->out_s, ds->width); - out_uint8(c->out_s, ds->bpp); - out_uint8(c->out_s, ds->idle_days); - out_uint8(c->out_s, ds->idle_hours); - out_uint8(c->out_s, ds->idle_minutes);*/ - /* these last three are not really needed... */ + /* session data */ + out_uint16_be(c->out_s, d); /* session display */ + /*out_uint8(c->out_s, ds->type); + out_uint16_be(c->out_s, ds->height); + out_uint16_be(c->out_s, ds->width); + out_uint8(c->out_s, ds->bpp); + out_uint8(c->out_s, ds->idle_days); + out_uint8(c->out_s, ds->idle_hours); + out_uint8(c->out_s, ds->idle_minutes);*/ + /* these last three are not really needed... */ - if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) + { + log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } - return SCP_SERVER_STATE_OK; + return SCP_SERVER_STATE_OK; } #endif diff --git a/sesman/libscp/libscp_v1s.h b/sesman/libscp/libscp_v1s.h index 32de0bba..5e3ec980 100644 --- a/sesman/libscp/libscp_v1s.h +++ b/sesman/libscp/libscp_v1s.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_v1s_mng.c b/sesman/libscp/libscp_v1s_mng.c index 599545ab..24553429 100644 --- a/sesman/libscp/libscp_v1s_mng.c +++ b/sesman/libscp/libscp_v1s_mng.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -33,309 +32,323 @@ //extern struct log_config* s_log; static enum SCP_SERVER_STATES_E -_scp_v1s_mng_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s); +_scp_v1s_mng_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s); /* server API */ enum SCP_SERVER_STATES_E -scp_v1s_mng_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s) +scp_v1s_mng_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s) { - struct SCP_SESSION* session; - tui32 ipaddr; - tui16 cmd; - tui8 sz; - char buf[257]; + struct SCP_SESSION *session; + tui32 ipaddr; + tui16 cmd; + tui8 sz; + char buf[257]; - /* reading command */ - in_uint16_be(c->in_s, cmd); - if (cmd != 1) /* manager login */ - { - return SCP_SERVER_STATE_SEQUENCE_ERR; - } + /* reading command */ + in_uint16_be(c->in_s, cmd); - session = scp_session_create(); - if (0 == session) - { - return SCP_SERVER_STATE_INTERNAL_ERR; - } + if (cmd != 1) /* manager login */ + { + return SCP_SERVER_STATE_SEQUENCE_ERR; + } - scp_session_set_version(session, 1); - scp_session_set_type(session, SCP_SESSION_TYPE_MANAGE); + session = scp_session_create(); - /* reading username */ - in_uint8(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_username(session, buf)) - { - scp_session_destroy(session); - return SCP_SERVER_STATE_INTERNAL_ERR; - } + if (0 == session) + { + return SCP_SERVER_STATE_INTERNAL_ERR; + } - /* reading password */ - in_uint8(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_password(session, buf)) - { - scp_session_destroy(session); - return SCP_SERVER_STATE_INTERNAL_ERR; - } + scp_session_set_version(session, 1); + scp_session_set_type(session, SCP_SESSION_TYPE_MANAGE); - /* reading remote address */ - in_uint8(c->in_s, sz); - if (sz == SCP_ADDRESS_TYPE_IPV4) - { - in_uint32_be(c->in_s, ipaddr); - scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV4_BIN, &ipaddr); - } - else if (sz == SCP_ADDRESS_TYPE_IPV6) - { - in_uint8a(c->in_s, buf, 16); - scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV6_BIN, buf); - } + /* reading username */ + in_uint8(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); - /* reading hostname */ - in_uint8(c->in_s, sz); - buf[sz]='\0'; - in_uint8a(c->in_s, buf, sz); - if (0 != scp_session_set_hostname(session, buf)) - { - scp_session_destroy(session); - return SCP_SERVER_STATE_INTERNAL_ERR; - } + if (0 != scp_session_set_username(session, buf)) + { + scp_session_destroy(session); + return SCP_SERVER_STATE_INTERNAL_ERR; + } - /* returning the struct */ - (*s)=session; + /* reading password */ + in_uint8(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); - return SCP_SERVER_STATE_START_MANAGE; + if (0 != scp_session_set_password(session, buf)) + { + scp_session_destroy(session); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* reading remote address */ + in_uint8(c->in_s, sz); + + if (sz == SCP_ADDRESS_TYPE_IPV4) + { + in_uint32_be(c->in_s, ipaddr); + scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV4_BIN, &ipaddr); + } + else if (sz == SCP_ADDRESS_TYPE_IPV6) + { + in_uint8a(c->in_s, buf, 16); + scp_session_set_addr(session, SCP_ADDRESS_TYPE_IPV6_BIN, buf); + } + + /* reading hostname */ + in_uint8(c->in_s, sz); + buf[sz] = '\0'; + in_uint8a(c->in_s, buf, sz); + + if (0 != scp_session_set_hostname(session, buf)) + { + scp_session_destroy(session); + return SCP_SERVER_STATE_INTERNAL_ERR; + } + + /* returning the struct */ + (*s) = session; + + return SCP_SERVER_STATE_START_MANAGE; } /* 002 */ enum SCP_SERVER_STATES_E -scp_v1s_mng_allow_connection(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +scp_v1s_mng_allow_connection(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - init_stream(c->out_s,c->out_s->size); + init_stream(c->out_s, c->out_s->size); - out_uint32_be(c->out_s, 1); - /* packet size: 4 + 4 + 2 + 2 */ - /* version + size + cmdset + cmd */ - out_uint32_be(c->out_s, 12); - out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); - out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN_ALLOW); + out_uint32_be(c->out_s, 1); + /* packet size: 4 + 4 + 2 + 2 */ + /* version + size + cmdset + cmd */ + out_uint32_be(c->out_s, 12); + out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); + out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN_ALLOW); - if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, 12)) - { - return SCP_SERVER_STATE_NETWORK_ERR; - } + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, 12)) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } - return _scp_v1s_mng_check_response(c, s); + return _scp_v1s_mng_check_response(c, s); } /* 003 */ enum SCP_SERVER_STATES_E -scp_v1s_mng_deny_connection(struct SCP_CONNECTION* c, char* reason) +scp_v1s_mng_deny_connection(struct SCP_CONNECTION *c, char *reason) { - int rlen; + int rlen; - init_stream(c->out_s,c->out_s->size); + init_stream(c->out_s, c->out_s->size); - /* forcing message not to exceed 64k */ - rlen = g_strlen(reason); - if (rlen > 65535) - { - rlen = 65535; - } + /* forcing message not to exceed 64k */ + rlen = g_strlen(reason); - out_uint32_be(c->out_s, 1); - /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason)*/ - /* version + size + cmdset + cmd + msglen + msg */ - out_uint32_be(c->out_s, rlen+14); - out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); - out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN_DENY); - out_uint16_be(c->out_s, rlen); - out_uint8p(c->out_s, reason, rlen); + if (rlen > 65535) + { + rlen = 65535; + } - if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, rlen+14)) - { - return SCP_SERVER_STATE_NETWORK_ERR; - } + out_uint32_be(c->out_s, 1); + /* packet size: 4 + 4 + 2 + 2 + 2 + strlen(reason)*/ + /* version + size + cmdset + cmd + msglen + msg */ + out_uint32_be(c->out_s, rlen + 14); + out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); + out_uint16_be(c->out_s, SCP_CMD_MNG_LOGIN_DENY); + out_uint16_be(c->out_s, rlen); + out_uint8p(c->out_s, reason, rlen); - return SCP_SERVER_STATE_END; + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, rlen + 14)) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } + + return SCP_SERVER_STATE_END; } /* 006 */ enum SCP_SERVER_STATES_E -scp_v1s_mng_list_sessions(struct SCP_CONNECTION* c, struct SCP_SESSION* s, - int sescnt, struct SCP_DISCONNECTED_SESSION* ds) +scp_v1s_mng_list_sessions(struct SCP_CONNECTION *c, struct SCP_SESSION *s, + int sescnt, struct SCP_DISCONNECTED_SESSION *ds) { - tui32 version = 1; - tui32 size = 12; - tui16 cmd = SCP_CMD_MNG_LIST; - int pktcnt; - int idx; - int sidx; - int pidx; - struct SCP_DISCONNECTED_SESSION* cds; + tui32 version = 1; + tui32 size = 12; + tui16 cmd = SCP_CMD_MNG_LIST; + int pktcnt; + int idx; + int sidx; + int pidx; + struct SCP_DISCONNECTED_SESSION *cds; - /* calculating the number of packets to send */ - pktcnt=sescnt/SCP_SERVER_MAX_LIST_SIZE; - if ((sescnt%SCP_SERVER_MAX_LIST_SIZE)!=0) - { - pktcnt++; - } + /* calculating the number of packets to send */ + pktcnt = sescnt / SCP_SERVER_MAX_LIST_SIZE; - for (idx=0; idxout_s, c->out_s->size); - - /* size: ver+size+cmdset+cmd+sescnt+continue+count */ - size=4+4+2+2+4+1+1; - - /* header */ - s_push_layer(c->out_s, channel_hdr, 8); - out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); - out_uint16_be(c->out_s, cmd); - - /* session count */ - out_uint32_be(c->out_s, sescnt); - - /* setting the continue flag */ - if ((idx+1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt) + if ((sescnt % SCP_SERVER_MAX_LIST_SIZE) != 0) { - out_uint8(c->out_s, 0); - /* setting session count for this packet */ - pidx=sescnt-(idx*SCP_SERVER_MAX_LIST_SIZE); - out_uint8(c->out_s, pidx); - } - else - { - out_uint8(c->out_s, 1); - /* setting session count for this packet */ - pidx=SCP_SERVER_MAX_LIST_SIZE; - out_uint8(c->out_s, pidx); + pktcnt++; } - /* adding session descriptors */ - for (sidx=0; sidxout_s, c->out_s->size); - /* session data */ - out_uint32_be(c->out_s, cds->SID); /* session id */ - out_uint8(c->out_s, cds->type); - out_uint16_be(c->out_s, cds->height); - out_uint16_be(c->out_s, cds->width); - out_uint8(c->out_s, cds->bpp); - out_uint8(c->out_s, cds->idle_days); - out_uint8(c->out_s, cds->idle_hours); - out_uint8(c->out_s, cds->idle_minutes); - size += 13; + /* size: ver+size+cmdset+cmd+sescnt+continue+count */ + size = 4 + 4 + 2 + 2 + 4 + 1 + 1; - out_uint16_be(c->out_s, cds->conn_year); - out_uint8(c->out_s, cds->conn_month); - out_uint8(c->out_s, cds->conn_day); - out_uint8(c->out_s, cds->conn_hour); - out_uint8(c->out_s, cds->conn_minute); - out_uint8(c->out_s, cds->addr_type); - size += 7; + /* header */ + s_push_layer(c->out_s, channel_hdr, 8); + out_uint16_be(c->out_s, SCP_COMMAND_SET_MANAGE); + out_uint16_be(c->out_s, cmd); - if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4) - { - in_uint32_be(c->out_s, cds->ipv4addr); - size += 4; - } - else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6) - { - in_uint8a(c->out_s, cds->ipv6addr, 16); - size += 16; - } + /* session count */ + out_uint32_be(c->out_s, sescnt); + + /* setting the continue flag */ + if ((idx + 1)*SCP_SERVER_MAX_LIST_SIZE >= sescnt) + { + out_uint8(c->out_s, 0); + /* setting session count for this packet */ + pidx = sescnt - (idx * SCP_SERVER_MAX_LIST_SIZE); + out_uint8(c->out_s, pidx); + } + else + { + out_uint8(c->out_s, 1); + /* setting session count for this packet */ + pidx = SCP_SERVER_MAX_LIST_SIZE; + out_uint8(c->out_s, pidx); + } + + /* adding session descriptors */ + for (sidx = 0; sidx < pidx; sidx++) + { + /* shortcut to the current session to send */ + cds = ds + ((idx) * SCP_SERVER_MAX_LIST_SIZE) + sidx; + + /* session data */ + out_uint32_be(c->out_s, cds->SID); /* session id */ + out_uint8(c->out_s, cds->type); + out_uint16_be(c->out_s, cds->height); + out_uint16_be(c->out_s, cds->width); + out_uint8(c->out_s, cds->bpp); + out_uint8(c->out_s, cds->idle_days); + out_uint8(c->out_s, cds->idle_hours); + out_uint8(c->out_s, cds->idle_minutes); + size += 13; + + out_uint16_be(c->out_s, cds->conn_year); + out_uint8(c->out_s, cds->conn_month); + out_uint8(c->out_s, cds->conn_day); + out_uint8(c->out_s, cds->conn_hour); + out_uint8(c->out_s, cds->conn_minute); + out_uint8(c->out_s, cds->addr_type); + size += 7; + + if (cds->addr_type == SCP_ADDRESS_TYPE_IPV4) + { + in_uint32_be(c->out_s, cds->ipv4addr); + size += 4; + } + else if (cds->addr_type == SCP_ADDRESS_TYPE_IPV6) + { + in_uint8a(c->out_s, cds->ipv6addr, 16); + size += 16; + } + } + + s_pop_layer(c->out_s, channel_hdr); + out_uint32_be(c->out_s, version); + out_uint32_be(c->out_s, size); + + if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, size)) + { + log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } } - s_pop_layer(c->out_s, channel_hdr); - out_uint32_be(c->out_s, version); - out_uint32_be(c->out_s, size); - - if (0!=scp_tcp_force_send(c->in_sck, c->out_s->data, size)) - { - log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } - } - - return _scp_v1s_mng_check_response(c, s); + return _scp_v1s_mng_check_response(c, s); } static enum SCP_SERVER_STATES_E -_scp_v1s_mng_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +_scp_v1s_mng_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - tui32 version; - tui32 size; - tui16 cmd; -// tui8 dim; -// char buf[257]; + tui32 version; + tui32 size; + tui16 cmd; + // tui8 dim; + // char buf[257]; - init_stream(c->in_s, c->in_s->size); - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } + init_stream(c->in_s, c->in_s->size); - in_uint32_be(c->in_s, version); - if (version != 1) - { - log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: version error", __LINE__); - return SCP_SERVER_STATE_VERSION_ERR; - } + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } - in_uint32_be(c->in_s, size); + in_uint32_be(c->in_s, version); - init_stream(c->in_s, c->in_s->size); - /* read the rest of the packet */ - if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) - { - log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); - return SCP_SERVER_STATE_NETWORK_ERR; - } + if (version != 1) + { + log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: version error", __LINE__); + return SCP_SERVER_STATE_VERSION_ERR; + } + + in_uint32_be(c->in_s, size); + + init_stream(c->in_s, c->in_s->size); + + /* read the rest of the packet */ + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8)) + { + log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: network error", __LINE__); + return SCP_SERVER_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd != SCP_COMMAND_SET_MANAGE) + { + log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: sequence error", __LINE__); + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); + + if (cmd == SCP_CMD_MNG_LIST_REQ) /* request session list */ + { + log_message(LOG_LEVEL_INFO, "[v1s_mng:%d] request session list", __LINE__); + return SCP_SERVER_STATE_MNG_LISTREQ; + } + else if (cmd == SCP_CMD_MNG_ACTION) /* execute an action */ + { + /*in_uint8(c->in_s, dim); + buf[dim]='\0'; + in_uint8a(c->in_s, buf, dim); + scp_session_set_errstr(s, buf);*/ + + log_message(LOG_LEVEL_INFO, "[v1s_mng:%d] action request", __LINE__); + return SCP_SERVER_STATE_MNG_ACTION; + } + + /* else if (cmd == 20) / * password change * / + { + in_uint16_be(c->in_s, s->display); + + return SCP_SERVER_STATE_OK; + } + else if (cmd == 40) / * session list * / + { + return SCP_SERVER_STATE_SESSION_LIST; + }*/ - in_uint16_be(c->in_s, cmd); - if (cmd != SCP_COMMAND_SET_MANAGE) - { log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: sequence error", __LINE__); return SCP_SERVER_STATE_SEQUENCE_ERR; - } - - in_uint16_be(c->in_s, cmd); - if (cmd == SCP_CMD_MNG_LIST_REQ) /* request session list */ - { - log_message(LOG_LEVEL_INFO, "[v1s_mng:%d] request session list", __LINE__); - return SCP_SERVER_STATE_MNG_LISTREQ; - } - else if (cmd == SCP_CMD_MNG_ACTION) /* execute an action */ - { - /*in_uint8(c->in_s, dim); - buf[dim]='\0'; - in_uint8a(c->in_s, buf, dim); - scp_session_set_errstr(s, buf);*/ - - log_message(LOG_LEVEL_INFO, "[v1s_mng:%d] action request", __LINE__); - return SCP_SERVER_STATE_MNG_ACTION; - } - /* else if (cmd == 20) / * password change * / - { - in_uint16_be(c->in_s, s->display); - - return SCP_SERVER_STATE_OK; - } - else if (cmd == 40) / * session list * / - { - return SCP_SERVER_STATE_SESSION_LIST; - }*/ - - log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: sequence error", __LINE__); - return SCP_SERVER_STATE_SEQUENCE_ERR; } #endif diff --git a/sesman/libscp/libscp_v1s_mng.h b/sesman/libscp/libscp_v1s_mng.h index ab296632..72df9fa6 100644 --- a/sesman/libscp/libscp_v1s_mng.h +++ b/sesman/libscp/libscp_v1s_mng.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/libscp/libscp_vX.c b/sesman/libscp/libscp_vX.c index b121da2d..e590fe73 100644 --- a/sesman/libscp/libscp_vX.c +++ b/sesman/libscp/libscp_vX.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -28,26 +27,26 @@ #include "libscp_vX.h" /* server API */ -enum SCP_SERVER_STATES_E scp_vXs_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s) +enum SCP_SERVER_STATES_E scp_vXs_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s) { - tui32 version; + tui32 version; - /* reading version and packet size */ - if (0!=scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) - { - return SCP_SERVER_STATE_NETWORK_ERR; - } + /* reading version and packet size */ + if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } - in_uint32_be(c->in_s, version); + in_uint32_be(c->in_s, version); - if (version == 0) - { - return scp_v0s_accept(c, s, 1); - } - else if (version == 1) - { - return scp_v1s_accept(c, s, 1); - } + if (version == 0) + { + return scp_v0s_accept(c, s, 1); + } + else if (version == 1) + { + return scp_v1s_accept(c, s, 1); + } - return SCP_SERVER_STATE_VERSION_ERR; + return SCP_SERVER_STATE_VERSION_ERR; } diff --git a/sesman/libscp/libscp_vX.h b/sesman/libscp/libscp_vX.h index c59bc1af..a68a9ede 100644 --- a/sesman/libscp/libscp_vX.h +++ b/sesman/libscp/libscp_vX.h @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file libscp_vX.h * @brief libscp version neutral code header * @author Simone Fedele - * + * */ #ifndef LIBSCP_VX_H diff --git a/sesman/lock.c b/sesman/lock.c index 83023cba..dd78ebbe 100644 --- a/sesman/lock.c +++ b/sesman/lock.c @@ -1,29 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 - - session manager - linux only - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * session manager + * linux only + */ #include "sesman.h" -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ static tbus g_sync_mutex = 0; static tbus g_lock_chain = 0; @@ -34,90 +32,90 @@ static tbus g_lock_socket = 0; void APP_CC lock_init(void) { - g_sync_mutex = tc_mutex_create(); - g_lock_chain = tc_mutex_create(); - g_sync_sem = tc_sem_create(0); - g_lock_socket = tc_sem_create(1); + g_sync_mutex = tc_mutex_create(); + g_lock_chain = tc_mutex_create(); + g_sync_sem = tc_sem_create(0); + g_lock_socket = tc_sem_create(1); } /******************************************************************************/ void APP_CC lock_deinit(void) { - tc_mutex_delete(g_sync_mutex); - tc_mutex_delete(g_lock_chain); - tc_sem_delete(g_sync_sem); - tc_sem_delete(g_lock_socket); + tc_mutex_delete(g_sync_mutex); + tc_mutex_delete(g_lock_chain); + tc_sem_delete(g_sync_sem); + tc_sem_delete(g_lock_socket); } /******************************************************************************/ void APP_CC lock_chain_acquire(void) { - /* lock the chain */ - LOG_DBG("lock_chain_acquire()"); - tc_mutex_lock(g_lock_chain); + /* lock the chain */ + LOG_DBG("lock_chain_acquire()"); + tc_mutex_lock(g_lock_chain); } /******************************************************************************/ void APP_CC lock_chain_release(void) { - /* unlock the chain */ - LOG_DBG("lock_chain_release()"); - tc_mutex_unlock(g_lock_chain); + /* unlock the chain */ + LOG_DBG("lock_chain_release()"); + tc_mutex_unlock(g_lock_chain); } /******************************************************************************/ void APP_CC lock_socket_acquire(void) { - /* lock socket variable */ - LOG_DBG("lock_socket_acquire()"); - tc_sem_dec(g_lock_socket); + /* lock socket variable */ + LOG_DBG("lock_socket_acquire()"); + tc_sem_dec(g_lock_socket); } /******************************************************************************/ void APP_CC lock_socket_release(void) { - /* unlock socket variable */ - LOG_DBG("lock_socket_release()"); - tc_sem_inc(g_lock_socket); + /* unlock socket variable */ + LOG_DBG("lock_socket_release()"); + tc_sem_inc(g_lock_socket); } /******************************************************************************/ void APP_CC lock_sync_acquire(void) { - /* lock sync variable */ - LOG_DBG("lock_sync_acquire()"); - tc_mutex_lock(g_sync_mutex); + /* lock sync variable */ + LOG_DBG("lock_sync_acquire()"); + tc_mutex_lock(g_sync_mutex); } /******************************************************************************/ void APP_CC lock_sync_release(void) { - /* unlock socket variable */ - LOG_DBG("lock_sync_release()"); - tc_mutex_unlock(g_sync_mutex); + /* unlock socket variable */ + LOG_DBG("lock_sync_release()"); + tc_mutex_unlock(g_sync_mutex); } /******************************************************************************/ void APP_CC lock_sync_sem_acquire(void) { - /* dec sem */ - LOG_DBG("lock_sync_sem_acquire()"); - tc_sem_dec(g_sync_sem); + /* dec sem */ + LOG_DBG("lock_sync_sem_acquire()"); + tc_sem_dec(g_sync_sem); } /******************************************************************************/ void APP_CC lock_sync_sem_release(void) { - /* inc sem */ - LOG_DBG("lock_sync_sem_release()"); - tc_sem_inc(g_sync_sem); + /* inc sem */ + LOG_DBG("lock_sync_sem_release()"); + tc_sem_inc(g_sync_sem); } diff --git a/sesman/lock.h b/sesman/lock.h index 28c147f2..0b7c905f 100644 --- a/sesman/lock.h +++ b/sesman/lock.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef LOCK_H #define LOCK_H diff --git a/sesman/scp.c b/sesman/scp.c index bbe495ea..db97fda5 100644 --- a/sesman/scp.c +++ b/sesman/scp.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -31,72 +30,75 @@ #include "sesman.h" extern int g_thread_sck; /* in thread.c */ -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ /******************************************************************************/ -void* DEFAULT_CC -scp_process_start(void* sck) +void *DEFAULT_CC +scp_process_start(void *sck) { - struct SCP_CONNECTION scon; - struct SCP_SESSION* sdata; + struct SCP_CONNECTION scon; + struct SCP_SESSION *sdata; - /* making a local copy of the socket (it's on the stack) */ - /* probably this is just paranoia */ - scon.in_sck = g_thread_sck; - LOG_DBG("started scp thread on socket %d", scon.in_sck); + /* making a local copy of the socket (it's on the stack) */ + /* probably this is just paranoia */ + scon.in_sck = g_thread_sck; + LOG_DBG("started scp thread on socket %d", scon.in_sck); - /* unlocking g_thread_sck */ - lock_socket_release(); + /* unlocking g_thread_sck */ + lock_socket_release(); - make_stream(scon.in_s); - make_stream(scon.out_s); + make_stream(scon.in_s); + make_stream(scon.out_s); - init_stream(scon.in_s, 8192); - init_stream(scon.out_s, 8192); + init_stream(scon.in_s, 8192); + init_stream(scon.out_s, 8192); - switch (scp_vXs_accept(&scon, &(sdata))) - { - case SCP_SERVER_STATE_OK: - if (sdata->version == 0) - { - /* starts processing an scp v0 connection */ - LOG_DBG("accept ok, go on with scp v0\n",0); - scp_v0_process(&scon, sdata); - } - else - { - LOG_DBG("accept ok, go on with scp v1\n",0); - /*LOG_DBG("user: %s\npass: %s",sdata->username, sdata->password);*/ - scp_v1_process(&scon, sdata); - } - break; - case SCP_SERVER_STATE_START_MANAGE: - /* starting a management session */ - log_message(LOG_LEVEL_WARNING, - "starting a sesman management session..."); - scp_v1_mng_process(&scon, sdata); - break; - case SCP_SERVER_STATE_VERSION_ERR: - /* an unknown scp version was requested, so we shut down the */ - /* connection (and log the fact) */ - log_message(LOG_LEVEL_WARNING, - "unknown protocol version specified. connection refused."); - break; - case SCP_SERVER_STATE_NETWORK_ERR: - log_message(LOG_LEVEL_WARNING, "libscp network error."); - break; - case SCP_SERVER_STATE_SEQUENCE_ERR: - log_message(LOG_LEVEL_WARNING, "libscp sequence error."); - break; - case SCP_SERVER_STATE_INTERNAL_ERR: - /* internal error occurred (eg. malloc() error, ecc.) */ - log_message(LOG_LEVEL_ERROR, "libscp internal error occurred."); - break; - default: - log_message(LOG_LEVEL_ALWAYS, "unknown return from scp_vXs_accept()"); - } - g_tcp_close(scon.in_sck); - free_stream(scon.in_s); - free_stream(scon.out_s); - return 0; + switch (scp_vXs_accept(&scon, &(sdata))) + { + case SCP_SERVER_STATE_OK: + + if (sdata->version == 0) + { + /* starts processing an scp v0 connection */ + LOG_DBG("accept ok, go on with scp v0\n", 0); + scp_v0_process(&scon, sdata); + } + else + { + LOG_DBG("accept ok, go on with scp v1\n", 0); + /*LOG_DBG("user: %s\npass: %s",sdata->username, sdata->password);*/ + scp_v1_process(&scon, sdata); + } + + break; + case SCP_SERVER_STATE_START_MANAGE: + /* starting a management session */ + log_message(LOG_LEVEL_WARNING, + "starting a sesman management session..."); + scp_v1_mng_process(&scon, sdata); + break; + case SCP_SERVER_STATE_VERSION_ERR: + /* an unknown scp version was requested, so we shut down the */ + /* connection (and log the fact) */ + log_message(LOG_LEVEL_WARNING, + "unknown protocol version specified. connection refused."); + break; + case SCP_SERVER_STATE_NETWORK_ERR: + log_message(LOG_LEVEL_WARNING, "libscp network error."); + break; + case SCP_SERVER_STATE_SEQUENCE_ERR: + log_message(LOG_LEVEL_WARNING, "libscp sequence error."); + break; + case SCP_SERVER_STATE_INTERNAL_ERR: + /* internal error occurred (eg. malloc() error, ecc.) */ + log_message(LOG_LEVEL_ERROR, "libscp internal error occurred."); + break; + default: + log_message(LOG_LEVEL_ALWAYS, "unknown return from scp_vXs_accept()"); + } + + g_tcp_close(scon.in_sck); + free_stream(scon.in_s); + free_stream(scon.out_s); + return 0; } diff --git a/sesman/scp.h b/sesman/scp.h index b3433f4e..c4f3de3a 100644 --- a/sesman/scp.h +++ b/sesman/scp.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/scp_v0.c b/sesman/scp_v0.c index dac04ad3..da6ab919 100644 --- a/sesman/scp_v0.c +++ b/sesman/scp_v0.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -27,121 +26,128 @@ #include "sesman.h" -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ /******************************************************************************/ void DEFAULT_CC -scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +scp_v0_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - int display = 0; - tbus data; - struct session_item* s_item; + int display = 0; + tbus data; + struct session_item *s_item; - data = auth_userpass(s->username, s->password); - if (s->type == SCP_GW_AUTHENTICATION) - { - /* this is just authentication in a gateway situation */ - /* g_writeln("SCP_GW_AUTHENTICATION message received"); */ - if (data) + data = auth_userpass(s->username, s->password); + + if (s->type == SCP_GW_AUTHENTICATION) { - if (1 == access_login_allowed(s->username)) - { - /* the user is member of the correct groups. */ - scp_v0s_replyauthentication(c, 0); - log_message(LOG_LEVEL_INFO, "Access permitted for user: %s", - s->username); - /* g_writeln("Connection allowed"); */ - } - else - { - scp_v0s_replyauthentication(c,3); - log_message(LOG_LEVEL_INFO, "Username okey but group problem for " - "user: %s", s->username); - /* g_writeln("user password ok, but group problem"); */ - } - } - else - { - /* g_writeln("username or password error"); */ - log_message(LOG_LEVEL_INFO, "Username or password error for user: %s", - s->username); - scp_v0s_replyauthentication(c, 2); - } - auth_end(data); - } - else if (data) - { - s_item = session_get_bydata(s->username, s->width, s->height, - s->bpp, s->type); - if (s_item != 0) - { - display = s_item->display; - if (0 != s->client_ip) - { - log_message( LOG_LEVEL_INFO, "++ reconnected session: username %s, " - "display :%d.0, session_pid %d, ip %s", - s->username, display, s_item->pid, s->client_ip); - } - else - { - log_message(LOG_LEVEL_INFO, "++ reconnected session: username %s, " - "display :%d.0, session_pid %d", s->username, display, - s_item->pid); - } - session_reconnect(display, s->username); - auth_end(data); - /* don't set data to null here */ - } - else - { - LOG_DBG("pre auth"); - if (1 == access_login_allowed(s->username)) - { - if (0 != s->client_ip) + /* this is just authentication in a gateway situation */ + /* g_writeln("SCP_GW_AUTHENTICATION message received"); */ + if (data) { - log_message(LOG_LEVEL_INFO, "++ created session (access granted): " - "username %s, ip %s", s->username, s->client_ip); + if (1 == access_login_allowed(s->username)) + { + /* the user is member of the correct groups. */ + scp_v0s_replyauthentication(c, 0); + log_message(LOG_LEVEL_INFO, "Access permitted for user: %s", + s->username); + /* g_writeln("Connection allowed"); */ + } + else + { + scp_v0s_replyauthentication(c, 3); + log_message(LOG_LEVEL_INFO, "Username okey but group problem for " + "user: %s", s->username); + /* g_writeln("user password ok, but group problem"); */ + } } else { - log_message(LOG_LEVEL_INFO, "++ created session (access granted): " - "username %s", s->username); + /* g_writeln("username or password error"); */ + log_message(LOG_LEVEL_INFO, "Username or password error for user: %s", + s->username); + scp_v0s_replyauthentication(c, 2); } - if (SCP_SESSION_TYPE_XVNC == s->type) + auth_end(data); + } + else if (data) + { + s_item = session_get_bydata(s->username, s->width, s->height, + s->bpp, s->type); + + if (s_item != 0) { - log_message( LOG_LEVEL_INFO, "starting Xvnc session..."); - display = session_start(s->width, s->height, s->bpp, s->username, - s->password, data, SESMAN_SESSION_TYPE_XVNC, - s->domain, s->program, s->directory, - s->client_ip); + display = s_item->display; + + if (0 != s->client_ip) + { + log_message( LOG_LEVEL_INFO, "++ reconnected session: username %s, " + "display :%d.0, session_pid %d, ip %s", + s->username, display, s_item->pid, s->client_ip); + } + else + { + log_message(LOG_LEVEL_INFO, "++ reconnected session: username %s, " + "display :%d.0, session_pid %d", s->username, display, + s_item->pid); + } + + session_reconnect(display, s->username); + auth_end(data); + /* don't set data to null here */ } else { - log_message(LOG_LEVEL_INFO, "starting X11rdp session..."); - display = session_start(s->width, s->height, s->bpp, s->username, - s->password, data, SESMAN_SESSION_TYPE_XRDP, - s->domain, s->program, s->directory, - s->client_ip); + LOG_DBG("pre auth"); + + if (1 == access_login_allowed(s->username)) + { + if (0 != s->client_ip) + { + log_message(LOG_LEVEL_INFO, "++ created session (access granted): " + "username %s, ip %s", s->username, s->client_ip); + } + else + { + log_message(LOG_LEVEL_INFO, "++ created session (access granted): " + "username %s", s->username); + } + + if (SCP_SESSION_TYPE_XVNC == s->type) + { + log_message( LOG_LEVEL_INFO, "starting Xvnc session..."); + display = session_start(s->width, s->height, s->bpp, s->username, + s->password, data, SESMAN_SESSION_TYPE_XVNC, + s->domain, s->program, s->directory, + s->client_ip); + } + else + { + log_message(LOG_LEVEL_INFO, "starting X11rdp session..."); + display = session_start(s->width, s->height, s->bpp, s->username, + s->password, data, SESMAN_SESSION_TYPE_XRDP, + s->domain, s->program, s->directory, + s->client_ip); + } + } + else + { + display = 0; + } + } + + if (display == 0) + { + auth_end(data); + scp_v0s_deny_connection(c); + } + else + { + scp_v0s_allow_connection(c, display); } - } - else - { - display = 0; - } - } - if (display == 0) - { - auth_end(data); - scp_v0s_deny_connection(c); } else { - scp_v0s_allow_connection(c, display); + scp_v0s_deny_connection(c); } - } - else - { - scp_v0s_deny_connection(c); - } } diff --git a/sesman/scp_v0.h b/sesman/scp_v0.h index 64d2475a..e5c2f576 100644 --- a/sesman/scp_v0.h +++ b/sesman/scp_v0.h @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file scp_v0.h * @brief scp version 0 declarations * @author Simone Fedele - * + * */ #ifndef SCP_V0_H @@ -38,7 +37,7 @@ * @param out_s output stream * */ -void DEFAULT_CC +void DEFAULT_CC scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s); #endif diff --git a/sesman/scp_v1.c b/sesman/scp_v1.c index f93f89ee..295fbce4 100644 --- a/sesman/scp_v1.c +++ b/sesman/scp_v1.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -30,203 +29,213 @@ //#include "libscp_types.h" #include "libscp.h" -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ -static void parseCommonStates(enum SCP_SERVER_STATES_E e, char* f); +static void parseCommonStates(enum SCP_SERVER_STATES_E e, char *f); /******************************************************************************/ void DEFAULT_CC -scp_v1_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +scp_v1_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - long data; - int display; - int retries; - int current_try; - enum SCP_SERVER_STATES_E e; - struct SCP_DISCONNECTED_SESSION* slist; - struct session_item* sitem; - int scount; - SCP_SID sid; + long data; + int display; + int retries; + int current_try; + enum SCP_SERVER_STATES_E e; + struct SCP_DISCONNECTED_SESSION *slist; + struct session_item *sitem; + int scount; + SCP_SID sid; - retries = g_cfg->sec.login_retry; - current_try = retries; + retries = g_cfg->sec.login_retry; + current_try = retries; - data = auth_userpass(s->username, s->password); - /*LOG_DBG("user: %s\npass: %s", s->username, s->password);*/ + data = auth_userpass(s->username, s->password); + /*LOG_DBG("user: %s\npass: %s", s->username, s->password);*/ - while ((!data) && ((retries == 0) || (current_try > 0))) - { - LOG_DBG("data %d - retry %d - currenttry %d - expr %d", - data, retries, current_try, - ((!data) && ((retries == 0) || (current_try > 0)))); - - e = scp_v1s_request_password(c, s, "Wrong username and/or password"); - - switch (e) + while ((!data) && ((retries == 0) || (current_try > 0))) { - case SCP_SERVER_STATE_OK: - /* all ok, we got new username and password */ - data = auth_userpass(s->username, s->password); - /* one try less */ - if (current_try > 0) + LOG_DBG("data %d - retry %d - currenttry %d - expr %d", + data, retries, current_try, + ((!data) && ((retries == 0) || (current_try > 0)))); + + e = scp_v1s_request_password(c, s, "Wrong username and/or password"); + + switch (e) { - current_try--; + case SCP_SERVER_STATE_OK: + /* all ok, we got new username and password */ + data = auth_userpass(s->username, s->password); + + /* one try less */ + if (current_try > 0) + { + current_try--; + } + + break; + default: + /* we check the other errors */ + parseCommonStates(e, "scp_v1s_list_sessions()"); + scp_session_destroy(s); + return; + //break; } - break; - default: - /* we check the other errors */ - parseCommonStates(e, "scp_v1s_list_sessions()"); + } + + if (!data) + { + scp_v1s_deny_connection(c, "Login failed"); + log_message( LOG_LEVEL_INFO, + "Login failed for user %s. Connection terminated", s->username); scp_session_destroy(s); return; - //break; - } - } - - if (!data) - { - scp_v1s_deny_connection(c, "Login failed"); - log_message( LOG_LEVEL_INFO, - "Login failed for user %s. Connection terminated", s->username); - scp_session_destroy(s); - return; - } - - /* testing if login is allowed*/ - if (0 == access_login_allowed(s->username)) - { - scp_v1s_deny_connection(c, "Access to Terminal Server not allowed."); - log_message(LOG_LEVEL_INFO, - "User %s not allowed on TS. Connection terminated", s->username); - scp_session_destroy(s); - return; - } - - //check if we need password change - - /* list disconnected sessions */ - slist = session_get_byuser(s->username, &scount, SESMAN_SESSION_STATUS_DISCONNECTED); - - if (scount == 0) - { - /* no disconnected sessions - start a new one */ - log_message(LOG_LEVEL_DEBUG,"No disconnected sessions for this user" - "- we create a new one"); - if (0 != s->client_ip) - { - log_message(LOG_LEVEL_INFO, "++ created session (access granted): username %s, ip %s", s->username, s->client_ip); - } - else - { - log_message(LOG_LEVEL_INFO, "++ created session (access granted): username %s", s->username); - } - if (SCP_SESSION_TYPE_XVNC == s->type) - { - log_message(LOG_LEVEL_INFO, "starting Xvnc session..."); - display = session_start(s->width, s->height, s->bpp, s->username, - s->password, data, SESMAN_SESSION_TYPE_XVNC, - s->domain, s->program, s->directory, s->client_ip); - } - else - { - log_message(LOG_LEVEL_INFO, "starting X11rdp session..."); - display = session_start(s->width, s->height, s->bpp, s->username, - s->password, data, SESMAN_SESSION_TYPE_XRDP, - s->domain, s->program, s->directory, s->client_ip); } - e = scp_v1s_connect_new_session(c, display); - switch (e) + /* testing if login is allowed*/ + if (0 == access_login_allowed(s->username)) { - case SCP_SERVER_STATE_OK: - /* all ok, we got new username and password */ - break; - default: - /* we check the other errors */ - parseCommonStates(e, "scp_v1s_connect_new_session()"); - break; + scp_v1s_deny_connection(c, "Access to Terminal Server not allowed."); + log_message(LOG_LEVEL_INFO, + "User %s not allowed on TS. Connection terminated", s->username); + scp_session_destroy(s); + return; } - } - else - { - /* one or more disconnected sessions - listing */ - e = scp_v1s_list_sessions(c, scount, slist, &sid); - switch (e) + //check if we need password change + + /* list disconnected sessions */ + slist = session_get_byuser(s->username, &scount, SESMAN_SESSION_STATUS_DISCONNECTED); + + if (scount == 0) { - /*case SCP_SERVER_STATE_FORCE_NEW:*/ - /* we should check for MaxSessions */ - case SCP_SERVER_STATE_SELECTION_CANCEL: - log_message( LOG_LEVEL_INFO, "Connection cancelled after session listing"); - break; - case SCP_SERVER_STATE_OK: - /* ok, reconnecting... */ - sitem=session_get_bypid(sid); - if (0 == sitem) + /* no disconnected sessions - start a new one */ + log_message(LOG_LEVEL_DEBUG, "No disconnected sessions for this user" + "- we create a new one"); + + if (0 != s->client_ip) { - e = scp_v1s_connection_error(c, "Internal error"); - log_message(LOG_LEVEL_INFO, "Cannot find session item on the chain"); + log_message(LOG_LEVEL_INFO, "++ created session (access granted): username %s, ip %s", s->username, s->client_ip); } else { - display = sitem->display; - /*e=scp_v1s_reconnect_session(c, sitem, display);*/ - e=scp_v1s_reconnect_session(c, display); - if (0 != s->client_ip) - { - log_message(LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d, ip %s", s->username, display, sitem->pid, s->client_ip); - } - else - { - log_message(LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d", s->username, display, sitem->pid); - } - g_free(sitem); + log_message(LOG_LEVEL_INFO, "++ created session (access granted): username %s", s->username); + } + + if (SCP_SESSION_TYPE_XVNC == s->type) + { + log_message(LOG_LEVEL_INFO, "starting Xvnc session..."); + display = session_start(s->width, s->height, s->bpp, s->username, + s->password, data, SESMAN_SESSION_TYPE_XVNC, + s->domain, s->program, s->directory, s->client_ip); + } + else + { + log_message(LOG_LEVEL_INFO, "starting X11rdp session..."); + display = session_start(s->width, s->height, s->bpp, s->username, + s->password, data, SESMAN_SESSION_TYPE_XRDP, + s->domain, s->program, s->directory, s->client_ip); + } + + e = scp_v1s_connect_new_session(c, display); + + switch (e) + { + case SCP_SERVER_STATE_OK: + /* all ok, we got new username and password */ + break; + default: + /* we check the other errors */ + parseCommonStates(e, "scp_v1s_connect_new_session()"); + break; } - break; - default: - /* we check the other errors */ - parseCommonStates(e, "scp_v1s_list_sessions()"); - break; } - g_free(slist); - } + else + { + /* one or more disconnected sessions - listing */ + e = scp_v1s_list_sessions(c, scount, slist, &sid); - /* resource management */ - if ((e == SCP_SERVER_STATE_OK) && (s->rsr)) - { - /* here goes scp resource sharing code */ - } + switch (e) + { + /*case SCP_SERVER_STATE_FORCE_NEW:*/ + /* we should check for MaxSessions */ + case SCP_SERVER_STATE_SELECTION_CANCEL: + log_message( LOG_LEVEL_INFO, "Connection cancelled after session listing"); + break; + case SCP_SERVER_STATE_OK: + /* ok, reconnecting... */ + sitem = session_get_bypid(sid); - /* cleanup */ - scp_session_destroy(s); - auth_end(data); + if (0 == sitem) + { + e = scp_v1s_connection_error(c, "Internal error"); + log_message(LOG_LEVEL_INFO, "Cannot find session item on the chain"); + } + else + { + display = sitem->display; + /*e=scp_v1s_reconnect_session(c, sitem, display);*/ + e = scp_v1s_reconnect_session(c, display); + + if (0 != s->client_ip) + { + log_message(LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d, ip %s", s->username, display, sitem->pid, s->client_ip); + } + else + { + log_message(LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d", s->username, display, sitem->pid); + } + + g_free(sitem); + } + + break; + default: + /* we check the other errors */ + parseCommonStates(e, "scp_v1s_list_sessions()"); + break; + } + + g_free(slist); + } + + /* resource management */ + if ((e == SCP_SERVER_STATE_OK) && (s->rsr)) + { + /* here goes scp resource sharing code */ + } + + /* cleanup */ + scp_session_destroy(s); + auth_end(data); } -static void parseCommonStates(enum SCP_SERVER_STATES_E e, char* f) +static void parseCommonStates(enum SCP_SERVER_STATES_E e, char *f) { - switch (e) - { - case SCP_SERVER_STATE_VERSION_ERR: - LOG_DBG("version error") - case SCP_SERVER_STATE_SIZE_ERR: - /* an unknown scp version was requested, so we shut down the */ - /* connection (and log the fact) */ - log_message(LOG_LEVEL_WARNING, - "protocol violation. connection closed."); - break; - case SCP_SERVER_STATE_NETWORK_ERR: - log_message(LOG_LEVEL_WARNING, "libscp network error."); - break; - case SCP_SERVER_STATE_SEQUENCE_ERR: - log_message(LOG_LEVEL_WARNING, "libscp sequence error."); - break; - case SCP_SERVER_STATE_INTERNAL_ERR: - /* internal error occurred (eg. malloc() error, ecc.) */ - log_message(LOG_LEVEL_ERROR, "libscp internal error occurred."); - break; - default: - /* dummy: scp_v1s_request_password won't generate any other */ - /* error other than the ones before */ - log_message(LOG_LEVEL_ALWAYS, "unknown return from %s", f); - break; - } + switch (e) + { + case SCP_SERVER_STATE_VERSION_ERR: + LOG_DBG("version error") + case SCP_SERVER_STATE_SIZE_ERR: + /* an unknown scp version was requested, so we shut down the */ + /* connection (and log the fact) */ + log_message(LOG_LEVEL_WARNING, + "protocol violation. connection closed."); + break; + case SCP_SERVER_STATE_NETWORK_ERR: + log_message(LOG_LEVEL_WARNING, "libscp network error."); + break; + case SCP_SERVER_STATE_SEQUENCE_ERR: + log_message(LOG_LEVEL_WARNING, "libscp sequence error."); + break; + case SCP_SERVER_STATE_INTERNAL_ERR: + /* internal error occurred (eg. malloc() error, ecc.) */ + log_message(LOG_LEVEL_ERROR, "libscp internal error occurred."); + break; + default: + /* dummy: scp_v1s_request_password won't generate any other */ + /* error other than the ones before */ + log_message(LOG_LEVEL_ALWAYS, "unknown return from %s", f); + break; + } } diff --git a/sesman/scp_v1.h b/sesman/scp_v1.h index 648855f9..0d224129 100644 --- a/sesman/scp_v1.h +++ b/sesman/scp_v1.h @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file scp_v1.h * @brief scp version 1 declarations * @author Simone Fedele - * + * */ #ifndef SCP_V1_H @@ -36,7 +35,7 @@ * @param out_s output stream * */ -void DEFAULT_CC +void DEFAULT_CC scp_v1_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s); #endif diff --git a/sesman/scp_v1_mng.c b/sesman/scp_v1_mng.c index e4d97b77..0e20007d 100644 --- a/sesman/scp_v1_mng.c +++ b/sesman/scp_v1_mng.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -29,112 +28,113 @@ #include "libscp.h" -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ -static void parseCommonStates(enum SCP_SERVER_STATES_E e, char* f); +static void parseCommonStates(enum SCP_SERVER_STATES_E e, char *f); /******************************************************************************/ void DEFAULT_CC -scp_v1_mng_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +scp_v1_mng_process(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { - long data; - enum SCP_SERVER_STATES_E e; - struct SCP_DISCONNECTED_SESSION* slist = 0; - int scount; - int end = 0; + long data; + enum SCP_SERVER_STATES_E e; + struct SCP_DISCONNECTED_SESSION *slist = 0; + int scount; + int end = 0; - data = auth_userpass(s->username, s->password); - /*LOG_DBG("user: %s\npass: %s", s->username, s->password);*/ + data = auth_userpass(s->username, s->password); + /*LOG_DBG("user: %s\npass: %s", s->username, s->password);*/ - if (!data) - { - scp_v1s_mng_deny_connection(c, "Login failed"); - log_message(LOG_LEVEL_INFO, - "[MNG] Login failed for user %s. Connection terminated", s->username); + if (!data) + { + scp_v1s_mng_deny_connection(c, "Login failed"); + log_message(LOG_LEVEL_INFO, + "[MNG] Login failed for user %s. Connection terminated", s->username); + scp_session_destroy(s); + auth_end(data); + return; + } + + /* testing if login is allowed */ + if (0 == access_login_mng_allowed(s->username)) + { + scp_v1s_mng_deny_connection(c, "Access to Terminal Server not allowed."); + log_message(LOG_LEVEL_INFO, + "[MNG] User %s not allowed on TS. Connection terminated", s->username); + scp_session_destroy(s); + auth_end(data); + return; + } + + e = scp_v1s_mng_allow_connection(c, s); + + end = 1; + + while (end) + { + switch (e) + { + case SCP_SERVER_STATE_MNG_ACTION: + log_message(LOG_LEVEL_INFO, "Connection cancelled after session listing"); + break; + + case SCP_SERVER_STATE_MNG_LISTREQ: + /* list disconnected sessions */ + slist = session_get_byuser(NULL, &scount, SESMAN_SESSION_STATUS_ALL); + LOG_DBG("sessions on TS: %d (slist: %x)", scount, slist); + + if (0 == slist) + { + // e=scp_v1s_connection_error(c, "Internal error"); + log_message(LOG_LEVEL_INFO, "No sessions on Terminal Server"); + end = 0; + } + else + { + e = scp_v1s_mng_list_sessions(c, s, scount, slist); + g_free(slist); + } + + break; + default: + /* we check the other errors */ + parseCommonStates(e, "scp_v1s_mng_list_sessions()"); + end = 0; + break; + } + } + + /* cleanup */ scp_session_destroy(s); auth_end(data); - return; - } +} - /* testing if login is allowed */ - if (0 == access_login_mng_allowed(s->username)) - { - scp_v1s_mng_deny_connection(c, "Access to Terminal Server not allowed."); - log_message(LOG_LEVEL_INFO, - "[MNG] User %s not allowed on TS. Connection terminated", s->username); - scp_session_destroy(s); - auth_end(data); - return; - } - - e = scp_v1s_mng_allow_connection(c, s); - - end = 1; - while (end) - { +static void parseCommonStates(enum SCP_SERVER_STATES_E e, char *f) +{ switch (e) { - case SCP_SERVER_STATE_MNG_ACTION: - log_message(LOG_LEVEL_INFO, "Connection cancelled after session listing"); - break; - - case SCP_SERVER_STATE_MNG_LISTREQ: - /* list disconnected sessions */ - slist = session_get_byuser(NULL, &scount, SESMAN_SESSION_STATUS_ALL); - LOG_DBG("sessions on TS: %d (slist: %x)", scount, slist); - - if (0 == slist) - { -// e=scp_v1s_connection_error(c, "Internal error"); - log_message(LOG_LEVEL_INFO, "No sessions on Terminal Server"); - end = 0; - } - else - { - e = scp_v1s_mng_list_sessions(c, s, scount, slist); - g_free(slist); - } - - break; - default: - /* we check the other errors */ - parseCommonStates(e, "scp_v1s_mng_list_sessions()"); - end = 0; - break; + case SCP_SERVER_STATE_VERSION_ERR: + LOG_DBG("version error") + case SCP_SERVER_STATE_SIZE_ERR: + /* an unknown scp version was requested, so we shut down the */ + /* connection (and log the fact) */ + log_message(LOG_LEVEL_WARNING, + "protocol violation. connection closed."); + break; + case SCP_SERVER_STATE_NETWORK_ERR: + log_message(LOG_LEVEL_WARNING, "libscp network error."); + break; + case SCP_SERVER_STATE_SEQUENCE_ERR: + log_message(LOG_LEVEL_WARNING, "libscp sequence error."); + break; + case SCP_SERVER_STATE_INTERNAL_ERR: + /* internal error occurred (eg. malloc() error, ecc.) */ + log_message(LOG_LEVEL_ERROR, "libscp internal error occurred."); + break; + default: + /* dummy: scp_v1s_request_password won't generate any other */ + /* error other than the ones before */ + log_message(LOG_LEVEL_ALWAYS, "unknown return from %s", f); + break; } - } - - /* cleanup */ - scp_session_destroy(s); - auth_end(data); -} - -static void parseCommonStates(enum SCP_SERVER_STATES_E e, char* f) -{ - switch (e) - { - case SCP_SERVER_STATE_VERSION_ERR: - LOG_DBG("version error") - case SCP_SERVER_STATE_SIZE_ERR: - /* an unknown scp version was requested, so we shut down the */ - /* connection (and log the fact) */ - log_message(LOG_LEVEL_WARNING, - "protocol violation. connection closed."); - break; - case SCP_SERVER_STATE_NETWORK_ERR: - log_message(LOG_LEVEL_WARNING, "libscp network error."); - break; - case SCP_SERVER_STATE_SEQUENCE_ERR: - log_message(LOG_LEVEL_WARNING, "libscp sequence error."); - break; - case SCP_SERVER_STATE_INTERNAL_ERR: - /* internal error occurred (eg. malloc() error, ecc.) */ - log_message(LOG_LEVEL_ERROR, "libscp internal error occurred."); - break; - default: - /* dummy: scp_v1s_request_password won't generate any other */ - /* error other than the ones before */ - log_message(LOG_LEVEL_ALWAYS, "unknown return from %s", f); - break; - } } diff --git a/sesman/scp_v1_mng.h b/sesman/scp_v1_mng.h index d4ef88ae..0317ba5f 100644 --- a/sesman/scp_v1_mng.h +++ b/sesman/scp_v1_mng.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/sesman.c b/sesman/sesman.c index b882c49d..50652b37 100644 --- a/sesman/sesman.c +++ b/sesman/sesman.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -30,7 +29,7 @@ int g_sck; int g_pid; unsigned char g_fixedkey[8] = { 23, 82, 107, 6, 35, 78, 88, 7 }; -struct config_sesman* g_cfg; /* defined in config.h */ +struct config_sesman *g_cfg; /* defined in config.h */ tbus g_term_event = 0; tbus g_sync_event = 0; @@ -46,325 +45,346 @@ extern int g_thread_sck; /* in thread.c */ static void DEFAULT_CC sesman_main_loop(void) { - int in_sck; - int error; - int robjs_count; - int cont; - tbus sck_obj; - tbus robjs[8]; + int in_sck; + int error; + int robjs_count; + int cont; + tbus sck_obj; + tbus robjs[8]; + + /*main program loop*/ + log_message(LOG_LEVEL_INFO, "listening..."); + g_sck = g_tcp_socket(); + g_tcp_set_non_blocking(g_sck); + error = scp_tcp_bind(g_sck, g_cfg->listen_address, g_cfg->listen_port); - /*main program loop*/ - log_message(LOG_LEVEL_INFO, "listening..."); - g_sck = g_tcp_socket(); - g_tcp_set_non_blocking(g_sck); - error = scp_tcp_bind(g_sck, g_cfg->listen_address, g_cfg->listen_port); - if (error == 0) - { - error = g_tcp_listen(g_sck); if (error == 0) { - sck_obj = g_create_wait_obj_from_socket(g_sck, 0); - cont = 1; - while (cont) - { - /* build the wait obj list */ - robjs_count = 0; - robjs[robjs_count++] = sck_obj; - robjs[robjs_count++] = g_term_event; - robjs[robjs_count++] = g_sync_event; - /* wait */ - if (g_obj_wait(robjs, robjs_count, 0, 0, -1) != 0) + error = g_tcp_listen(g_sck); + + if (error == 0) { - /* error, should not get here */ - g_sleep(100); + sck_obj = g_create_wait_obj_from_socket(g_sck, 0); + cont = 1; + + while (cont) + { + /* build the wait obj list */ + robjs_count = 0; + robjs[robjs_count++] = sck_obj; + robjs[robjs_count++] = g_term_event; + robjs[robjs_count++] = g_sync_event; + + /* wait */ + if (g_obj_wait(robjs, robjs_count, 0, 0, -1) != 0) + { + /* error, should not get here */ + g_sleep(100); + } + + if (g_is_wait_obj_set(g_term_event)) /* term */ + { + break; + } + + if (g_is_wait_obj_set(g_sync_event)) /* sync */ + { + g_reset_wait_obj(g_sync_event); + session_sync_start(); + } + + if (g_is_wait_obj_set(sck_obj)) /* incoming connection */ + { + in_sck = g_tcp_accept(g_sck); + + if ((in_sck == -1) && g_tcp_last_error_would_block(g_sck)) + { + /* should not get here */ + g_sleep(100); + } + else if (in_sck == -1) + { + /* error, should not get here */ + break; + } + else + { + /* we've got a connection, so we pass it to scp code */ + LOG_DBG("new connection"); + thread_scp_start(in_sck); + /* todo, do we have to wait here ? */ + } + } + } + + g_delete_wait_obj_from_socket(sck_obj); } - if (g_is_wait_obj_set(g_term_event)) /* term */ + else { - break; + log_message(LOG_LEVEL_ERROR, "listen error %d (%s)", + g_get_errno(), g_get_strerror()); } - if (g_is_wait_obj_set(g_sync_event)) /* sync */ - { - g_reset_wait_obj(g_sync_event); - session_sync_start(); - } - if (g_is_wait_obj_set(sck_obj)) /* incoming connection */ - { - in_sck = g_tcp_accept(g_sck); - if ((in_sck == -1) && g_tcp_last_error_would_block(g_sck)) - { - /* should not get here */ - g_sleep(100); - } - else if (in_sck == -1) - { - /* error, should not get here */ - break; - } - else - { - /* we've got a connection, so we pass it to scp code */ - LOG_DBG("new connection"); - thread_scp_start(in_sck); - /* todo, do we have to wait here ? */ - } - } - } - g_delete_wait_obj_from_socket(sck_obj); } else { - log_message(LOG_LEVEL_ERROR, "listen error %d (%s)", - g_get_errno(), g_get_strerror()); + log_message(LOG_LEVEL_ERROR, "bind error on " + "port '%s': %d (%s)", g_cfg->listen_port, + g_get_errno(), g_get_strerror()); } - } - else - { - log_message(LOG_LEVEL_ERROR, "bind error on " - "port '%s': %d (%s)", g_cfg->listen_port, - g_get_errno(), g_get_strerror()); - } - g_tcp_close(g_sck); + + g_tcp_close(g_sck); } /******************************************************************************/ int DEFAULT_CC -main(int argc, char** argv) +main(int argc, char **argv) { - int fd; - enum logReturns error; - int daemon = 1; - int pid; - char pid_s[8]; - char text[256]; - char pid_file[256]; - char cfg_file[256]; + int fd; + enum logReturns error; + int daemon = 1; + int pid; + char pid_s[8]; + char text[256]; + char pid_file[256]; + char cfg_file[256]; - g_init("xrdp-sesman"); - g_snprintf(pid_file, 255, "%s/xrdp-sesman.pid", XRDP_PID_PATH); - if (1 == argc) - { - /* no options on command line. normal startup */ - g_printf("starting sesman...\n"); - daemon = 1; - } - else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--nodaemon")) || - (0 == g_strcasecmp(argv[1], "-nodaemon")) || - (0 == g_strcasecmp(argv[1], "-n")) || - (0 == g_strcasecmp(argv[1], "-ns")))) - { - /* starts sesman not daemonized */ - g_printf("starting sesman in foregroud...\n"); - daemon = 0; - } - else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--help")) || - (0 == g_strcasecmp(argv[1], "-help")) || - (0 == g_strcasecmp(argv[1], "-h")))) - { - /* help screen */ - g_printf("sesman - xrdp session manager\n\n"); - g_printf("usage: sesman [command]\n\n"); - g_printf("command can be one of the following:\n"); - g_printf("-n, -ns, --nodaemon starts sesman in foreground\n"); - g_printf("-k, --kill kills running sesman\n"); - g_printf("-h, --help shows this help\n"); - g_printf("if no command is specified, sesman is started in background"); - g_deinit(); - g_exit(0); - } - else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--kill")) || - (0 == g_strcasecmp(argv[1], "-kill")) || - (0 == g_strcasecmp(argv[1], "-k")))) - { - /* killing running sesman */ - /* check if sesman is running */ - if (!g_file_exist(pid_file)) + g_init("xrdp-sesman"); + g_snprintf(pid_file, 255, "%s/xrdp-sesman.pid", XRDP_PID_PATH); + + if (1 == argc) { - g_printf("sesman is not running (pid file not found - %s)\n", pid_file); - g_deinit(); - g_exit(1); + /* no options on command line. normal startup */ + g_printf("starting sesman...\n"); + daemon = 1; } - - fd = g_file_open(pid_file); - - if (-1 == fd) + else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--nodaemon")) || + (0 == g_strcasecmp(argv[1], "-nodaemon")) || + (0 == g_strcasecmp(argv[1], "-n")) || + (0 == g_strcasecmp(argv[1], "-ns")))) { - g_printf("error opening pid file[%s]: %s\n", pid_file, g_get_strerror()); - return 1; + /* starts sesman not daemonized */ + g_printf("starting sesman in foregroud...\n"); + daemon = 0; } - - error = g_file_read(fd, pid_s, 7); - if (-1 == error) + else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--help")) || + (0 == g_strcasecmp(argv[1], "-help")) || + (0 == g_strcasecmp(argv[1], "-h")))) { - g_printf("error reading pid file: %s\n", g_get_strerror()); - g_file_close(fd); - g_deinit(); - g_exit(error); + /* help screen */ + g_printf("sesman - xrdp session manager\n\n"); + g_printf("usage: sesman [command]\n\n"); + g_printf("command can be one of the following:\n"); + g_printf("-n, -ns, --nodaemon starts sesman in foreground\n"); + g_printf("-k, --kill kills running sesman\n"); + g_printf("-h, --help shows this help\n"); + g_printf("if no command is specified, sesman is started in background"); + g_deinit(); + g_exit(0); } - g_file_close(fd); - pid = g_atoi(pid_s); - - error = g_sigterm(pid); - if (0 != error) + else if ((2 == argc) && ((0 == g_strcasecmp(argv[1], "--kill")) || + (0 == g_strcasecmp(argv[1], "-kill")) || + (0 == g_strcasecmp(argv[1], "-k")))) { - g_printf("error killing sesman: %s\n", g_get_strerror()); + /* killing running sesman */ + /* check if sesman is running */ + if (!g_file_exist(pid_file)) + { + g_printf("sesman is not running (pid file not found - %s)\n", pid_file); + g_deinit(); + g_exit(1); + } + + fd = g_file_open(pid_file); + + if (-1 == fd) + { + g_printf("error opening pid file[%s]: %s\n", pid_file, g_get_strerror()); + return 1; + } + + error = g_file_read(fd, pid_s, 7); + + if (-1 == error) + { + g_printf("error reading pid file: %s\n", g_get_strerror()); + g_file_close(fd); + g_deinit(); + g_exit(error); + } + + g_file_close(fd); + pid = g_atoi(pid_s); + + error = g_sigterm(pid); + + if (0 != error) + { + g_printf("error killing sesman: %s\n", g_get_strerror()); + } + else + { + g_file_delete(pid_file); + } + + g_deinit(); + g_exit(error); } else { - g_file_delete(pid_file); + /* there's something strange on the command line */ + g_printf("sesman - xrdp session manager\n\n"); + g_printf("error: invalid command line\n"); + g_printf("usage: sesman [ --nodaemon | --kill | --help ]\n"); + g_deinit(); + g_exit(1); } - g_deinit(); - g_exit(error); - } - else - { - /* there's something strange on the command line */ - g_printf("sesman - xrdp session manager\n\n"); - g_printf("error: invalid command line\n"); - g_printf("usage: sesman [ --nodaemon | --kill | --help ]\n"); - g_deinit(); - g_exit(1); - } - if (g_file_exist(pid_file)) - { - g_printf("sesman is already running.\n"); - g_printf("if it's not running, try removing "); - g_printf(pid_file); - g_printf("\n"); - g_deinit(); - g_exit(1); - } - - /* reading config */ - g_cfg = g_malloc(sizeof(struct config_sesman), 1); - if (0 == g_cfg) - { - g_printf("error creating config: quitting.\n"); - g_deinit(); - g_exit(1); - } - //g_cfg->log.fd = -1; /* don't use logging before reading its config */ - if (0 != config_read(g_cfg)) - { - g_printf("error reading config: %s\nquitting.\n", g_get_strerror()); - g_deinit(); - g_exit(1); - } - - g_snprintf(cfg_file,255,"%s/sesman.ini",XRDP_CFG_PATH); - - /* starting logging subsystem */ - error = log_start(cfg_file,"XRDP-sesman"); - - if (error != LOG_STARTUP_OK) - { - switch (error) + if (g_file_exist(pid_file)) { - case LOG_ERROR_MALLOC: - g_writeln("error on malloc. cannot start logging. quitting."); - break; - case LOG_ERROR_FILE_OPEN: - g_writeln("error opening log file [%s]. quitting.", - getLogFile(text, 255)); - break; + g_printf("sesman is already running.\n"); + g_printf("if it's not running, try removing "); + g_printf(pid_file); + g_printf("\n"); + g_deinit(); + g_exit(1); } - g_deinit(); - g_exit(1); - } - /* libscp initialization */ - scp_init(); + /* reading config */ + g_cfg = g_malloc(sizeof(struct config_sesman), 1); - if (daemon) - { - /* start of daemonizing code */ - g_pid = g_fork(); - - if (0 != g_pid) + if (0 == g_cfg) { - g_deinit(); - g_exit(0); + g_printf("error creating config: quitting.\n"); + g_deinit(); + g_exit(1); } - g_file_close(0); - g_file_close(1); - g_file_close(2); + //g_cfg->log.fd = -1; /* don't use logging before reading its config */ + if (0 != config_read(g_cfg)) + { + g_printf("error reading config: %s\nquitting.\n", g_get_strerror()); + g_deinit(); + g_exit(1); + } - g_file_open("/dev/null"); - g_file_open("/dev/null"); - g_file_open("/dev/null"); - } + g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); - /* initializing locks */ - lock_init(); + /* starting logging subsystem */ + error = log_start(cfg_file, "XRDP-sesman"); - /* signal handling */ - g_pid = g_getpid(); - /* old style signal handling is now managed synchronously by a - * separate thread. uncomment this block if you need old style - * signal handling and comment out thread_sighandler_start() - * going back to old style for the time being - * problem with the sigaddset functions in sig.c - jts */ + if (error != LOG_STARTUP_OK) + { + switch (error) + { + case LOG_ERROR_MALLOC: + g_writeln("error on malloc. cannot start logging. quitting."); + break; + case LOG_ERROR_FILE_OPEN: + g_writeln("error opening log file [%s]. quitting.", + getLogFile(text, 255)); + break; + } + + g_deinit(); + g_exit(1); + } + + /* libscp initialization */ + scp_init(); + + if (daemon) + { + /* start of daemonizing code */ + g_pid = g_fork(); + + if (0 != g_pid) + { + g_deinit(); + g_exit(0); + } + + g_file_close(0); + g_file_close(1); + g_file_close(2); + + g_file_open("/dev/null"); + g_file_open("/dev/null"); + g_file_open("/dev/null"); + } + + /* initializing locks */ + lock_init(); + + /* signal handling */ + g_pid = g_getpid(); + /* old style signal handling is now managed synchronously by a + * separate thread. uncomment this block if you need old style + * signal handling and comment out thread_sighandler_start() + * going back to old style for the time being + * problem with the sigaddset functions in sig.c - jts */ #if 1 - g_signal_hang_up(sig_sesman_reload_cfg); /* SIGHUP */ - g_signal_user_interrupt(sig_sesman_shutdown); /* SIGINT */ - g_signal_kill(sig_sesman_shutdown); /* SIGKILL */ - g_signal_terminate(sig_sesman_shutdown); /* SIGTERM */ - g_signal_child_stop(sig_sesman_session_end); /* SIGCHLD */ + g_signal_hang_up(sig_sesman_reload_cfg); /* SIGHUP */ + g_signal_user_interrupt(sig_sesman_shutdown); /* SIGINT */ + g_signal_kill(sig_sesman_shutdown); /* SIGKILL */ + g_signal_terminate(sig_sesman_shutdown); /* SIGTERM */ + g_signal_child_stop(sig_sesman_session_end); /* SIGCHLD */ #endif #if 0 - thread_sighandler_start(); + thread_sighandler_start(); #endif - if (daemon) - { - /* writing pid file */ - fd = g_file_open(pid_file); - if (-1 == fd) + + if (daemon) { - log_message(LOG_LEVEL_ERROR, - "error opening pid file[%s]: %s", - pid_file, g_get_strerror()); - log_end(); - g_deinit(); - g_exit(1); + /* writing pid file */ + fd = g_file_open(pid_file); + + if (-1 == fd) + { + log_message(LOG_LEVEL_ERROR, + "error opening pid file[%s]: %s", + pid_file, g_get_strerror()); + log_end(); + g_deinit(); + g_exit(1); + } + + g_sprintf(pid_s, "%d", g_pid); + g_file_write(fd, pid_s, g_strlen(pid_s)); + g_file_close(fd); } - g_sprintf(pid_s, "%d", g_pid); - g_file_write(fd, pid_s, g_strlen(pid_s)); - g_file_close(fd); - } - /* start program main loop */ - log_message(LOG_LEVEL_ALWAYS, - "starting sesman with pid %d", g_pid); + /* start program main loop */ + log_message(LOG_LEVEL_ALWAYS, + "starting sesman with pid %d", g_pid); - /* make sure the /tmp/.X11-unix directory exist */ - if (!g_directory_exist("/tmp/.X11-unix")) - { - g_create_dir("/tmp/.X11-unix"); - g_chmod_hex("/tmp/.X11-unix", 0x1777); - } + /* make sure the /tmp/.X11-unix directory exist */ + if (!g_directory_exist("/tmp/.X11-unix")) + { + g_create_dir("/tmp/.X11-unix"); + g_chmod_hex("/tmp/.X11-unix", 0x1777); + } - g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_term", g_pid); - g_term_event = g_create_wait_obj(text); - g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_sync", g_pid); - g_sync_event = g_create_wait_obj(text); + g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_term", g_pid); + g_term_event = g_create_wait_obj(text); + g_snprintf(text, 255, "xrdp_sesman_%8.8x_main_sync", g_pid); + g_sync_event = g_create_wait_obj(text); - sesman_main_loop(); + sesman_main_loop(); - /* clean up PID file on exit */ - if (daemon) - { - g_file_delete(pid_file); - } + /* clean up PID file on exit */ + if (daemon) + { + g_file_delete(pid_file); + } - g_delete_wait_obj(g_term_event); - g_delete_wait_obj(g_sync_event); + g_delete_wait_obj(g_term_event); + g_delete_wait_obj(g_sync_event); - if (!daemon) - { - log_end(); - } + if (!daemon) + { + log_end(); + } - g_deinit(); - return 0; + g_deinit(); + return 0; } diff --git a/sesman/sesman.h b/sesman/sesman.h index 0344ccd5..2eb70df9 100644 --- a/sesman/sesman.h +++ b/sesman/sesman.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/session.c b/sesman/session.c index 94c5bf91..6f98fbc7 100644 --- a/sesman/session.c +++ b/sesman/session.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -33,19 +32,19 @@ extern tbus g_sync_event; extern unsigned char g_fixedkey[8]; -extern struct config_sesman* g_cfg; /* in sesman.c */ -struct session_chain* g_sessions; +extern struct config_sesman *g_cfg; /* in sesman.c */ +struct session_chain *g_sessions; int g_session_count; static int g_sync_width; static int g_sync_height; static int g_sync_bpp; -static char* g_sync_username; -static char* g_sync_password; -static char* g_sync_domain; -static char* g_sync_program; -static char* g_sync_directory; -static char* g_sync_client_ip; +static char *g_sync_username; +static char *g_sync_password; +static char *g_sync_domain; +static char *g_sync_program; +static char *g_sync_directory; +static char *g_sync_client_ip; static tbus g_sync_data; static tui8 g_sync_type; static int g_sync_result; @@ -58,87 +57,92 @@ static int g_sync_cmd; * @param len the allocated len for outstr * @return */ -char* APP_CC -dumpItemsToString(struct list* self, char *outstr, int len) +char *APP_CC +dumpItemsToString(struct list *self, char *outstr, int len) { - g_memset(outstr,0,len); - int index; - tbus item; - int totalLen= 0; + g_memset(outstr, 0, len); + int index; + tbus item; + int totalLen = 0; - if (self->count == 0) - { - g_writeln("List is empty"); - } - for (index = 0; index < self->count; index++) - { - /* +1 = one space*/ - totalLen = totalLen + g_strlen((char*)list_get_item(self, index))+1; - if(len>totalLen) + if (self->count == 0) { - g_strcat(outstr,(char*)list_get_item(self, index)); - g_strcat(outstr," "); + g_writeln("List is empty"); } - } - return outstr ; + + for (index = 0; index < self->count; index++) + { + /* +1 = one space*/ + totalLen = totalLen + g_strlen((char *)list_get_item(self, index)) + 1; + + if (len > totalLen) + { + g_strcat(outstr, (char *)list_get_item(self, index)); + g_strcat(outstr, " "); + } + } + + return outstr ; } /******************************************************************************/ -struct session_item* DEFAULT_CC -session_get_bydata(char* name, int width, int height, int bpp, int type) +struct session_item *DEFAULT_CC +session_get_bydata(char *name, int width, int height, int bpp, int type) { - struct session_chain* tmp; + struct session_chain *tmp; - /*THREAD-FIX require chain lock */ - lock_chain_acquire(); + /*THREAD-FIX require chain lock */ + lock_chain_acquire(); - tmp = g_sessions; + tmp = g_sessions; - /* convert from SCP_SESSION_TYPE namespace to SESMAN_SESSION_TYPE namespace */ - switch (type) - { - case SCP_SESSION_TYPE_XVNC: /* 0 */ - type = SESMAN_SESSION_TYPE_XVNC; /* 2 */ - break; - case SCP_SESSION_TYPE_XRDP: /* 1 */ - type = SESMAN_SESSION_TYPE_XRDP; /* 1 */ - break; - default: - lock_chain_release(); - return 0; - } - - while (tmp != 0) - { - if (type == SESMAN_SESSION_TYPE_XRDP) + /* convert from SCP_SESSION_TYPE namespace to SESMAN_SESSION_TYPE namespace */ + switch (type) { - /* only name and bpp need to match for X11rdp, it can resize */ - if (g_strncmp(name, tmp->item->name, 255) == 0 && - tmp->item->bpp == bpp && - tmp->item->type == type) - { - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return tmp->item; - } + case SCP_SESSION_TYPE_XVNC: /* 0 */ + type = SESMAN_SESSION_TYPE_XVNC; /* 2 */ + break; + case SCP_SESSION_TYPE_XRDP: /* 1 */ + type = SESMAN_SESSION_TYPE_XRDP; /* 1 */ + break; + default: + lock_chain_release(); + return 0; } - if (g_strncmp(name, tmp->item->name, 255) == 0 && - tmp->item->width == width && - tmp->item->height == height && - tmp->item->bpp == bpp && - tmp->item->type == type) - { - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return tmp->item; - } - tmp = tmp->next; - } - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return 0; + while (tmp != 0) + { + if (type == SESMAN_SESSION_TYPE_XRDP) + { + /* only name and bpp need to match for X11rdp, it can resize */ + if (g_strncmp(name, tmp->item->name, 255) == 0 && + tmp->item->bpp == bpp && + tmp->item->type == type) + { + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return tmp->item; + } + } + + if (g_strncmp(name, tmp->item->name, 255) == 0 && + tmp->item->width == width && + tmp->item->height == height && + tmp->item->bpp == bpp && + tmp->item->type == type) + { + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return tmp->item; + } + + tmp = tmp->next; + } + + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return 0; } /******************************************************************************/ @@ -152,39 +156,44 @@ session_get_bydata(char* name, int width, int height, int bpp, int type) static int DEFAULT_CC x_server_running_check_ports(int display) { - char text[256]; - int x_running; - int sck; + char text[256]; + int x_running; + int sck; - g_sprintf(text, "/tmp/.X11-unix/X%d", display); - x_running = g_file_exist(text); - if (!x_running) - { - g_sprintf(text, "/tmp/.X%d-lock", display); + g_sprintf(text, "/tmp/.X11-unix/X%d", display); x_running = g_file_exist(text); - } - if (!x_running) /* check 59xx */ - { - sck = g_tcp_socket(); - g_sprintf(text, "59%2.2d", display); - x_running = g_tcp_bind(sck, text); - g_tcp_close(sck); - } - if (!x_running) /* check 60xx */ - { - sck = g_tcp_socket(); - g_sprintf(text, "60%2.2d", display); - x_running = g_tcp_bind(sck, text); - g_tcp_close(sck); - } - if (!x_running) /* check 62xx */ - { - sck = g_tcp_socket(); - g_sprintf(text, "62%2.2d", display); - x_running = g_tcp_bind(sck, text); - g_tcp_close(sck); - } - return x_running; + + if (!x_running) + { + g_sprintf(text, "/tmp/.X%d-lock", display); + x_running = g_file_exist(text); + } + + if (!x_running) /* check 59xx */ + { + sck = g_tcp_socket(); + g_sprintf(text, "59%2.2d", display); + x_running = g_tcp_bind(sck, text); + g_tcp_close(sck); + } + + if (!x_running) /* check 60xx */ + { + sck = g_tcp_socket(); + g_sprintf(text, "60%2.2d", display); + x_running = g_tcp_bind(sck, text); + g_tcp_close(sck); + } + + if (!x_running) /* check 62xx */ + { + sck = g_tcp_socket(); + g_sprintf(text, "62%2.2d", display); + x_running = g_tcp_bind(sck, text); + g_tcp_close(sck); + } + + return x_running; } /******************************************************************************/ @@ -198,83 +207,87 @@ x_server_running_check_ports(int display) static int DEFAULT_CC x_server_running(int display) { - char text[256]; - int x_running; - int sck; + char text[256]; + int x_running; + int sck; - g_sprintf(text, "/tmp/.X11-unix/X%d", display); - x_running = g_file_exist(text); - if (!x_running) - { - g_sprintf(text, "/tmp/.X%d-lock", display); + g_sprintf(text, "/tmp/.X11-unix/X%d", display); x_running = g_file_exist(text); - } - return x_running; + + if (!x_running) + { + g_sprintf(text, "/tmp/.X%d-lock", display); + x_running = g_file_exist(text); + } + + return x_running; } /******************************************************************************/ static void DEFAULT_CC -session_start_sessvc(int xpid, int wmpid, long data, char* username, int display) +session_start_sessvc(int xpid, int wmpid, long data, char *username, int display) { - struct list * sessvc_params = (struct list *)NULL; - char wmpid_str[25]; - char xpid_str[25]; - char exe_path[262]; - int i = 0; + struct list *sessvc_params = (struct list *)NULL; + char wmpid_str[25]; + char xpid_str[25]; + char exe_path[262]; + int i = 0; - /* initialize (zero out) local variables: */ - g_memset(wmpid_str,0,sizeof(char) * 25); - g_memset(xpid_str,0,sizeof(char) * 25); - g_memset(exe_path,0,sizeof(char) * 262); + /* initialize (zero out) local variables: */ + g_memset(wmpid_str, 0, sizeof(char) * 25); + g_memset(xpid_str, 0, sizeof(char) * 25); + g_memset(exe_path, 0, sizeof(char) * 262); - /* new style waiting for clients */ - g_sprintf(wmpid_str, "%d", wmpid); - g_sprintf(xpid_str, "%d", xpid); - log_message(LOG_LEVEL_INFO, - "starting xrdp-sessvc - xpid=%s - wmpid=%s", - xpid_str, wmpid_str); + /* new style waiting for clients */ + g_sprintf(wmpid_str, "%d", wmpid); + g_sprintf(xpid_str, "%d", xpid); + log_message(LOG_LEVEL_INFO, + "starting xrdp-sessvc - xpid=%s - wmpid=%s", + xpid_str, wmpid_str); - sessvc_params = list_create(); - sessvc_params->auto_free = 1; + sessvc_params = list_create(); + sessvc_params->auto_free = 1; - /* building parameters */ - g_snprintf(exe_path, 261, "%s/xrdp-sessvc", XRDP_SBIN_PATH); + /* building parameters */ + g_snprintf(exe_path, 261, "%s/xrdp-sessvc", XRDP_SBIN_PATH); - list_add_item(sessvc_params, (long)g_strdup(exe_path)); - list_add_item(sessvc_params, (long)g_strdup(xpid_str)); - list_add_item(sessvc_params, (long)g_strdup(wmpid_str)); - list_add_item(sessvc_params, 0); /* mandatory */ + list_add_item(sessvc_params, (long)g_strdup(exe_path)); + list_add_item(sessvc_params, (long)g_strdup(xpid_str)); + list_add_item(sessvc_params, (long)g_strdup(wmpid_str)); + list_add_item(sessvc_params, 0); /* mandatory */ - env_set_user(username, 0, display); + env_set_user(username, 0, display); - /* executing sessvc */ - g_execvp(exe_path, ((char**)sessvc_params->items)); + /* executing sessvc */ + g_execvp(exe_path, ((char **)sessvc_params->items)); - /* should not get here */ - log_message(LOG_LEVEL_ALWAYS, - "error starting xrdp-sessvc - pid %d - xpid=%s - wmpid=%s", - g_getpid(), xpid_str, wmpid_str); + /* should not get here */ + log_message(LOG_LEVEL_ALWAYS, + "error starting xrdp-sessvc - pid %d - xpid=%s - wmpid=%s", + g_getpid(), xpid_str, wmpid_str); - /* logging parameters */ - /* no problem calling strerror for thread safety: other threads - are blocked */ - log_message(LOG_LEVEL_DEBUG, "errno: %d, description: %s", - errno, g_get_strerror()); - log_message(LOG_LEVEL_DEBUG, "execve parameter list:"); - for (i = 0; i < (sessvc_params->count); i++) - { - log_message(LOG_LEVEL_DEBUG, " argv[%d] = %s", i, - (char*)list_get_item(sessvc_params, i)); - } - list_delete(sessvc_params); + /* logging parameters */ + /* no problem calling strerror for thread safety: other threads + are blocked */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, description: %s", + errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "execve parameter list:"); - /* keep the old waitpid if some error occurs during execlp */ - g_waitpid(wmpid); - g_sigterm(xpid); - g_sigterm(wmpid); - g_sleep(1000); - auth_end(data); - g_exit(0); + for (i = 0; i < (sessvc_params->count); i++) + { + log_message(LOG_LEVEL_DEBUG, " argv[%d] = %s", i, + (char *)list_get_item(sessvc_params, i)); + } + + list_delete(sessvc_params); + + /* keep the old waitpid if some error occurs during execlp */ + g_waitpid(wmpid); + g_sigterm(xpid); + g_sigterm(wmpid); + g_sleep(1000); + auth_end(data); + g_exit(0); } /******************************************************************************/ @@ -283,20 +296,24 @@ session_start_sessvc(int xpid, int wmpid, long data, char* username, int display static int APP_CC session_is_display_in_chain(int display) { - struct session_chain* chain; - struct session_item* item; + struct session_chain *chain; + struct session_item *item; - chain = g_sessions; - while (chain != 0) - { - item = chain->item; - if (item->display == display) + chain = g_sessions; + + while (chain != 0) { - return 1; + item = chain->item; + + if (item->display == display) + { + return 1; + } + + chain = chain->next; } - chain = chain->next; - } - return 0; + + return 0; } /******************************************************************************/ @@ -304,412 +321,442 @@ session_is_display_in_chain(int display) static int APP_CC session_get_aval_display_from_chain(void) { - int display; + int display; - display = g_cfg->sess.x11_display_offset; - lock_chain_acquire(); - while ((display - g_cfg->sess.x11_display_offset) <= g_cfg->sess.max_sessions) - { - if (!session_is_display_in_chain(display)) + display = g_cfg->sess.x11_display_offset; + lock_chain_acquire(); + + while ((display - g_cfg->sess.x11_display_offset) <= g_cfg->sess.max_sessions) { - if (!x_server_running_check_ports(display)) - { - lock_chain_release(); - return display; - } + if (!session_is_display_in_chain(display)) + { + if (!x_server_running_check_ports(display)) + { + lock_chain_release(); + return display; + } + } + + display++; } - display++; - } - lock_chain_release(); - log_message(LOG_LEVEL_ERROR, "X server -- no display in range is available"); - return 0; + + lock_chain_release(); + log_message(LOG_LEVEL_ERROR, "X server -- no display in range is available"); + return 0; } /******************************************************************************/ static int APP_CC wait_for_xserver(int display) { - int i; + int i; - /* give X a bit to start */ - /* wait up to 10 secs for x server to start */ - i = 0; - while (!x_server_running(display)) - { - i++; - if (i > 40) + /* give X a bit to start */ + /* wait up to 10 secs for x server to start */ + i = 0; + + while (!x_server_running(display)) { - log_message(LOG_LEVEL_ERROR, - "X server for display %d startup timeout", - display); - break; + i++; + + if (i > 40) + { + log_message(LOG_LEVEL_ERROR, + "X server for display %d startup timeout", + display); + break; + } + + g_sleep(250); } - g_sleep(250); - } - return 0; + + return 0; } /******************************************************************************/ /* called with the main thread */ static int APP_CC -session_start_fork(int width, int height, int bpp, char* username, - char* password, tbus data, tui8 type, char* domain, - char* program, char* directory, char* client_ip) +session_start_fork(int width, int height, int bpp, char *username, + char *password, tbus data, tui8 type, char *domain, + char *program, char *directory, char *client_ip) { - int display = 0; - int pid = 0; - int wmpid = 0; - int xpid = 0; - int i = 0; - char geometry[32]; - char depth[32]; - char screen[32]; - char text[256]; - char passwd_file[256]; - char ** pp1 = (char **)NULL; - struct session_chain * temp = (struct session_chain *)NULL; - struct list * xserver_params = (struct list *)NULL; - time_t ltime; - struct tm stime; - char execvpparams[2048]; + int display = 0; + int pid = 0; + int wmpid = 0; + int xpid = 0; + int i = 0; + char geometry[32]; + char depth[32]; + char screen[32]; + char text[256]; + char passwd_file[256]; + char **pp1 = (char **)NULL; + struct session_chain *temp = (struct session_chain *)NULL; + struct list *xserver_params = (struct list *)NULL; + time_t ltime; + struct tm stime; + char execvpparams[2048]; - /* initialize (zero out) local variables: */ - g_memset(<ime,0,sizeof(time_t)); - g_memset(&stime,0,sizeof(struct tm)); - g_memset(geometry,0,sizeof(char) * 32); - g_memset(depth,0,sizeof(char) * 32); - g_memset(screen,0,sizeof(char) * 32); - g_memset(text,0,sizeof(char) * 256); - g_memset(passwd_file,0,sizeof(char) * 256); + /* initialize (zero out) local variables: */ + g_memset(<ime, 0, sizeof(time_t)); + g_memset(&stime, 0, sizeof(struct tm)); + g_memset(geometry, 0, sizeof(char) * 32); + g_memset(depth, 0, sizeof(char) * 32); + g_memset(screen, 0, sizeof(char) * 32); + g_memset(text, 0, sizeof(char) * 256); + g_memset(passwd_file, 0, sizeof(char) * 256); - /* check to limit concurrent sessions */ - if (g_session_count >= g_cfg->sess.max_sessions) - { - log_message(LOG_LEVEL_INFO, "max concurrent session limit " - "exceeded. login for user %s denied", username); - return 0; - } + /* check to limit concurrent sessions */ + if (g_session_count >= g_cfg->sess.max_sessions) + { + log_message(LOG_LEVEL_INFO, "max concurrent session limit " + "exceeded. login for user %s denied", username); + return 0; + } - temp = (struct session_chain*)g_malloc(sizeof(struct session_chain), 0); - if (temp == 0) - { - log_message(LOG_LEVEL_ERROR, "cannot create new chain " - "element - user %s", username); - return 0; - } - temp->item = (struct session_item*)g_malloc(sizeof(struct session_item), 0); - if (temp->item == 0) - { - g_free(temp); - log_message(LOG_LEVEL_ERROR, "cannot create new session " - "item - user %s", username); - return 0; - } - display = session_get_aval_display_from_chain(); - if (display == 0) - { - g_free(temp->item); - g_free(temp); - return 0; - } - pid = g_fork(); - if (pid == -1) - { - } - else if (pid == 0) /* child sesman */ - { - auth_start_session(data, display); - g_sprintf(geometry, "%dx%d", width, height); - g_sprintf(depth, "%d", bpp); - g_sprintf(screen, ":%d", display); - wmpid = g_fork(); - if (wmpid == -1) + temp = (struct session_chain *)g_malloc(sizeof(struct session_chain), 0); + + if (temp == 0) + { + log_message(LOG_LEVEL_ERROR, "cannot create new chain " + "element - user %s", username); + return 0; + } + + temp->item = (struct session_item *)g_malloc(sizeof(struct session_item), 0); + + if (temp->item == 0) + { + g_free(temp); + log_message(LOG_LEVEL_ERROR, "cannot create new session " + "item - user %s", username); + return 0; + } + + display = session_get_aval_display_from_chain(); + + if (display == 0) + { + g_free(temp->item); + g_free(temp); + return 0; + } + + pid = g_fork(); + + if (pid == -1) { } - else if (wmpid == 0) /* child (child sesman) xserver */ + else if (pid == 0) /* child sesman */ { - wait_for_xserver(display); - env_set_user(username, 0, display); - if (x_server_running(display)) - { - auth_set_env(data); - if (directory != 0) - { - if (directory[0] != 0) - { - g_set_current_dir(directory); - } - } - if (program != 0) - { - if (program[0] != 0) - { - g_execlp3(program, program, 0); - log_message(LOG_LEVEL_ALWAYS, - "error starting program %s for user %s - pid %d", - program, username, g_getpid()); - } - } - /* try to execute user window manager if enabled */ - if (g_cfg->enable_user_wm) - { - g_sprintf(text,"%s/%s", g_getenv("HOME"), g_cfg->user_wm); - if (g_file_exist(text)) - { - g_execlp3(text, g_cfg->user_wm, 0); - log_message(LOG_LEVEL_ALWAYS,"error starting user " - "wm for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message(LOG_LEVEL_DEBUG, "errno: %d, " - "description: %s", errno, g_get_strerror()); - log_message(LOG_LEVEL_DEBUG,"execlp3 parameter " - "list:"); - log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", - text); - log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", - g_cfg->user_wm); - } - } - /* if we're here something happened to g_execlp3 - so we try running the default window manager */ - g_sprintf(text, "%s/%s", XRDP_CFG_PATH, g_cfg->default_wm); - g_execlp3(text, g_cfg->default_wm, 0); + auth_start_session(data, display); + g_sprintf(geometry, "%dx%d", width, height); + g_sprintf(depth, "%d", bpp); + g_sprintf(screen, ":%d", display); + wmpid = g_fork(); - log_message( LOG_LEVEL_ALWAYS,"error starting default " - "wm for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message( LOG_LEVEL_DEBUG, "errno: %d, description: " - "%s", errno, g_get_strerror()); - log_message(LOG_LEVEL_DEBUG,"execlp3 parameter list:"); - log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", - text); - log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", - g_cfg->default_wm); + if (wmpid == -1) + { + } + else if (wmpid == 0) /* child (child sesman) xserver */ + { + wait_for_xserver(display); + env_set_user(username, 0, display); - /* still a problem starting window manager just start xterm */ - g_execlp3("xterm", "xterm", 0); + if (x_server_running(display)) + { + auth_set_env(data); - /* should not get here */ - log_message(LOG_LEVEL_ALWAYS,"error starting xterm " - "for user %s - pid %d", username, g_getpid()); - /* logging parameters */ - log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " - "%s", errno, g_get_strerror()); - } - else - { - log_message(LOG_LEVEL_ERROR, "another Xserver might " - "already be active on display %d - see log", display); - } - log_message(LOG_LEVEL_DEBUG,"aborting connection..."); - g_exit(0); + if (directory != 0) + { + if (directory[0] != 0) + { + g_set_current_dir(directory); + } + } + + if (program != 0) + { + if (program[0] != 0) + { + g_execlp3(program, program, 0); + log_message(LOG_LEVEL_ALWAYS, + "error starting program %s for user %s - pid %d", + program, username, g_getpid()); + } + } + + /* try to execute user window manager if enabled */ + if (g_cfg->enable_user_wm) + { + g_sprintf(text, "%s/%s", g_getenv("HOME"), g_cfg->user_wm); + + if (g_file_exist(text)) + { + g_execlp3(text, g_cfg->user_wm, 0); + log_message(LOG_LEVEL_ALWAYS, "error starting user " + "wm for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, " + "description: %s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "execlp3 parameter " + "list:"); + log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", + text); + log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", + g_cfg->user_wm); + } + } + + /* if we're here something happened to g_execlp3 + so we try running the default window manager */ + g_sprintf(text, "%s/%s", XRDP_CFG_PATH, g_cfg->default_wm); + g_execlp3(text, g_cfg->default_wm, 0); + + log_message( LOG_LEVEL_ALWAYS, "error starting default " + "wm for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message( LOG_LEVEL_DEBUG, "errno: %d, description: " + "%s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "execlp3 parameter list:"); + log_message(LOG_LEVEL_DEBUG, " argv[0] = %s", + text); + log_message(LOG_LEVEL_DEBUG, " argv[1] = %s", + g_cfg->default_wm); + + /* still a problem starting window manager just start xterm */ + g_execlp3("xterm", "xterm", 0); + + /* should not get here */ + log_message(LOG_LEVEL_ALWAYS, "error starting xterm " + "for user %s - pid %d", username, g_getpid()); + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " + "%s", errno, g_get_strerror()); + } + else + { + log_message(LOG_LEVEL_ERROR, "another Xserver might " + "already be active on display %d - see log", display); + } + + log_message(LOG_LEVEL_DEBUG, "aborting connection..."); + g_exit(0); + } + else /* parent (child sesman) */ + { + xpid = g_fork(); + + if (xpid == -1) + { + } + else if (xpid == 0) /* child */ + { + env_set_user(username, passwd_file, display); + env_check_password_file(passwd_file, password); + + if (type == SESMAN_SESSION_TYPE_XVNC) + { + xserver_params = list_create(); + xserver_params->auto_free = 1; + /* these are the must have parameters */ + list_add_item(xserver_params, (long)g_strdup("Xvnc")); + list_add_item(xserver_params, (long)g_strdup(screen)); + list_add_item(xserver_params, (long)g_strdup("-geometry")); + list_add_item(xserver_params, (long)g_strdup(geometry)); + list_add_item(xserver_params, (long)g_strdup("-depth")); + list_add_item(xserver_params, (long)g_strdup(depth)); + list_add_item(xserver_params, (long)g_strdup("-rfbauth")); + list_add_item(xserver_params, (long)g_strdup(passwd_file)); + + /* additional parameters from sesman.ini file */ + //config_read_xserver_params(SESMAN_SESSION_TYPE_XVNC, + // xserver_params); + list_append_list_strdup(g_cfg->vnc_params, xserver_params, 0); + + /* make sure it ends with a zero */ + list_add_item(xserver_params, 0); + pp1 = (char **)xserver_params->items; + log_message(LOG_LEVEL_INFO, "Xvnc start:%s", dumpItemsToString(xserver_params, execvpparams, 2048)); + g_execvp("Xvnc", pp1); + } + else if (type == SESMAN_SESSION_TYPE_XRDP) + { + xserver_params = list_create(); + xserver_params->auto_free = 1; + /* these are the must have parameters */ + list_add_item(xserver_params, (long)g_strdup("X11rdp")); + list_add_item(xserver_params, (long)g_strdup(screen)); + list_add_item(xserver_params, (long)g_strdup("-geometry")); + list_add_item(xserver_params, (long)g_strdup(geometry)); + list_add_item(xserver_params, (long)g_strdup("-depth")); + list_add_item(xserver_params, (long)g_strdup(depth)); + + /* additional parameters from sesman.ini file */ + //config_read_xserver_params(SESMAN_SESSION_TYPE_XRDP, + // xserver_params); + list_append_list_strdup(g_cfg->rdp_params, xserver_params, 0); + + /* make sure it ends with a zero */ + list_add_item(xserver_params, 0); + pp1 = (char **)xserver_params->items; + log_message(LOG_LEVEL_INFO, "X11rdp start:%s", dumpItemsToString(xserver_params, execvpparams, 2048)); + g_execvp("X11rdp", pp1); + } + else + { + log_message(LOG_LEVEL_ALWAYS, "bad session type - " + "user %s - pid %d", username, g_getpid()); + g_exit(1); + } + + /* should not get here */ + log_message(LOG_LEVEL_ALWAYS, "error starting X server " + "- user %s - pid %d", username, g_getpid()); + + /* logging parameters */ + log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " + "%s", errno, g_get_strerror()); + log_message(LOG_LEVEL_DEBUG, "execve parameter list size: " + "%d", (xserver_params)->count); + + for (i = 0; i < (xserver_params->count); i++) + { + log_message(LOG_LEVEL_DEBUG, " argv[%d] = %s", + i, (char *)list_get_item(xserver_params, i)); + } + + list_delete(xserver_params); + g_exit(1); + } + else /* parent (child sesman)*/ + { + wait_for_xserver(display); + g_snprintf(text, 255, "%d", display); + g_setenv("XRDP_SESSVC_DISPLAY", text, 1); + g_snprintf(text, 255, ":%d.0", display); + g_setenv("DISPLAY", text, 1); + /* new style waiting for clients */ + session_start_sessvc(xpid, wmpid, data, username, display); + } + } } - else /* parent (child sesman) */ + else /* parent sesman process */ { - xpid = g_fork(); - if (xpid == -1) - { - } - else if (xpid == 0) /* child */ - { - env_set_user(username, passwd_file, display); - env_check_password_file(passwd_file, password); - if (type == SESMAN_SESSION_TYPE_XVNC) - { - xserver_params = list_create(); - xserver_params->auto_free = 1; - /* these are the must have parameters */ - list_add_item(xserver_params, (long)g_strdup("Xvnc")); - list_add_item(xserver_params, (long)g_strdup(screen)); - list_add_item(xserver_params, (long)g_strdup("-geometry")); - list_add_item(xserver_params, (long)g_strdup(geometry)); - list_add_item(xserver_params, (long)g_strdup("-depth")); - list_add_item(xserver_params, (long)g_strdup(depth)); - list_add_item(xserver_params, (long)g_strdup("-rfbauth")); - list_add_item(xserver_params, (long)g_strdup(passwd_file)); + temp->item->pid = pid; + temp->item->display = display; + temp->item->width = width; + temp->item->height = height; + temp->item->bpp = bpp; + temp->item->data = data; + g_strncpy(temp->item->client_ip, client_ip, 255); /* store client ip data */ + g_strncpy(temp->item->name, username, 255); - /* additional parameters from sesman.ini file */ - //config_read_xserver_params(SESMAN_SESSION_TYPE_XVNC, - // xserver_params); - list_append_list_strdup(g_cfg->vnc_params, xserver_params, 0); + ltime = g_time1(); + localtime_r(<ime, &stime); + temp->item->connect_time.year = (tui16)(stime.tm_year + 1900); + temp->item->connect_time.month = (tui8)stime.tm_mon; + temp->item->connect_time.day = (tui8)stime.tm_mday; + temp->item->connect_time.hour = (tui8)stime.tm_hour; + temp->item->connect_time.minute = (tui8)stime.tm_min; + zero_time(&(temp->item->disconnect_time)); + zero_time(&(temp->item->idle_time)); - /* make sure it ends with a zero */ - list_add_item(xserver_params, 0); - pp1 = (char**)xserver_params->items; - log_message(LOG_LEVEL_INFO,"Xvnc start:%s",dumpItemsToString(xserver_params, execvpparams, 2048)); - g_execvp("Xvnc", pp1); - } - else if (type == SESMAN_SESSION_TYPE_XRDP) - { - xserver_params = list_create(); - xserver_params->auto_free = 1; - /* these are the must have parameters */ - list_add_item(xserver_params, (long)g_strdup("X11rdp")); - list_add_item(xserver_params, (long)g_strdup(screen)); - list_add_item(xserver_params, (long)g_strdup("-geometry")); - list_add_item(xserver_params, (long)g_strdup(geometry)); - list_add_item(xserver_params, (long)g_strdup("-depth")); - list_add_item(xserver_params, (long)g_strdup(depth)); + temp->item->type = type; + temp->item->status = SESMAN_SESSION_STATUS_ACTIVE; - /* additional parameters from sesman.ini file */ - //config_read_xserver_params(SESMAN_SESSION_TYPE_XRDP, - // xserver_params); - list_append_list_strdup(g_cfg->rdp_params, xserver_params, 0); - - /* make sure it ends with a zero */ - list_add_item(xserver_params, 0); - pp1 = (char**)xserver_params->items; - log_message(LOG_LEVEL_INFO,"X11rdp start:%s",dumpItemsToString(xserver_params, execvpparams, 2048)); - g_execvp("X11rdp", pp1); - } - else - { - log_message(LOG_LEVEL_ALWAYS, "bad session type - " - "user %s - pid %d", username, g_getpid()); - g_exit(1); - } - - /* should not get here */ - log_message(LOG_LEVEL_ALWAYS, "error starting X server " - "- user %s - pid %d", username, g_getpid()); - - /* logging parameters */ - log_message(LOG_LEVEL_DEBUG, "errno: %d, description: " - "%s", errno, g_get_strerror()); - log_message(LOG_LEVEL_DEBUG, "execve parameter list size: " - "%d", (xserver_params)->count); - - for (i=0; i<(xserver_params->count); i++) - { - log_message(LOG_LEVEL_DEBUG, " argv[%d] = %s", - i, (char*)list_get_item(xserver_params, i)); - } - list_delete(xserver_params); - g_exit(1); - } - else /* parent (child sesman)*/ - { - wait_for_xserver(display); - g_snprintf(text, 255, "%d", display); - g_setenv("XRDP_SESSVC_DISPLAY", text, 1); - g_snprintf(text, 255, ":%d.0", display); - g_setenv("DISPLAY", text, 1); - /* new style waiting for clients */ - session_start_sessvc(xpid, wmpid, data, username, display); - } + temp->next = g_sessions; + g_sessions = temp; + g_session_count++; } - } - else /* parent sesman process */ - { - temp->item->pid = pid; - temp->item->display = display; - temp->item->width = width; - temp->item->height = height; - temp->item->bpp = bpp; - temp->item->data = data; - g_strncpy(temp->item->client_ip, client_ip, 255); /* store client ip data */ - g_strncpy(temp->item->name, username, 255); - ltime = g_time1(); - localtime_r(<ime, &stime); - temp->item->connect_time.year = (tui16)(stime.tm_year + 1900); - temp->item->connect_time.month = (tui8)stime.tm_mon; - temp->item->connect_time.day = (tui8)stime.tm_mday; - temp->item->connect_time.hour = (tui8)stime.tm_hour; - temp->item->connect_time.minute = (tui8)stime.tm_min; - zero_time(&(temp->item->disconnect_time)); - zero_time(&(temp->item->idle_time)); - - temp->item->type=type; - temp->item->status=SESMAN_SESSION_STATUS_ACTIVE; - - temp->next=g_sessions; - g_sessions=temp; - g_session_count++; - } - return display; + return display; } /******************************************************************************/ /* called with the main thread */ static int APP_CC -session_reconnect_fork(int display, char* username) +session_reconnect_fork(int display, char *username) { - int pid; - char text[256]; + int pid; + char text[256]; - pid = g_fork(); - if (pid == -1) - { - } - else if (pid == 0) - { - env_set_user(username, 0, display); - g_snprintf(text, 255, "%s/%s", XRDP_CFG_PATH, "reconnectwm.sh"); - if (g_file_exist(text)) + pid = g_fork(); + + if (pid == -1) { - g_execlp3(text, g_cfg->default_wm, 0); } - g_exit(0); - } - return display; + else if (pid == 0) + { + env_set_user(username, 0, display); + g_snprintf(text, 255, "%s/%s", XRDP_CFG_PATH, "reconnectwm.sh"); + + if (g_file_exist(text)) + { + g_execlp3(text, g_cfg->default_wm, 0); + } + + g_exit(0); + } + + return display; } /******************************************************************************/ /* called by a worker thread, ask the main thread to call session_sync_start and wait till done */ int DEFAULT_CC -session_start(int width, int height, int bpp, char* username, char* password, - long data, tui8 type, char* domain, char* program, - char* directory, char* client_ip) +session_start(int width, int height, int bpp, char *username, char *password, + long data, tui8 type, char *domain, char *program, + char *directory, char *client_ip) { - int display; + int display; - /* lock mutex */ - lock_sync_acquire(); - /* set shared vars */ - g_sync_cmd = 0; - g_sync_width = width; - g_sync_height = height; - g_sync_bpp = bpp; - g_sync_username = username; - g_sync_password = password; - g_sync_domain = domain; - g_sync_program = program; - g_sync_directory = directory; - g_sync_client_ip = client_ip; - g_sync_data = data; - g_sync_type = type; - /* set event for main thread to see */ - g_set_wait_obj(g_sync_event); - /* wait for main thread to get done */ - lock_sync_sem_acquire(); - /* read result(display) from shared var */ - display = g_sync_result; - /* unlock mutex */ - lock_sync_release(); - return display; + /* lock mutex */ + lock_sync_acquire(); + /* set shared vars */ + g_sync_cmd = 0; + g_sync_width = width; + g_sync_height = height; + g_sync_bpp = bpp; + g_sync_username = username; + g_sync_password = password; + g_sync_domain = domain; + g_sync_program = program; + g_sync_directory = directory; + g_sync_client_ip = client_ip; + g_sync_data = data; + g_sync_type = type; + /* set event for main thread to see */ + g_set_wait_obj(g_sync_event); + /* wait for main thread to get done */ + lock_sync_sem_acquire(); + /* read result(display) from shared var */ + display = g_sync_result; + /* unlock mutex */ + lock_sync_release(); + return display; } /******************************************************************************/ /* called by a worker thread, ask the main thread to call session_sync_start and wait till done */ int DEFAULT_CC -session_reconnect(int display, char* username) +session_reconnect(int display, char *username) { - /* lock mutex */ - lock_sync_acquire(); - /* set shared vars */ - g_sync_cmd = 1; - g_sync_width = display; - g_sync_username = username; - /* set event for main thread to see */ - g_set_wait_obj(g_sync_event); - /* wait for main thread to get done */ - lock_sync_sem_acquire(); - /* unlock mutex */ - lock_sync_release(); - return 0; + /* lock mutex */ + lock_sync_acquire(); + /* set shared vars */ + g_sync_cmd = 1; + g_sync_width = display; + g_sync_username = username; + /* set event for main thread to see */ + g_set_wait_obj(g_sync_event); + /* wait for main thread to get done */ + lock_sync_sem_acquire(); + /* unlock mutex */ + lock_sync_release(); + return 0; } /******************************************************************************/ @@ -717,267 +764,279 @@ session_reconnect(int display, char* username) int APP_CC session_sync_start(void) { - if (g_sync_cmd == 0) - { - g_sync_result = session_start_fork(g_sync_width, g_sync_height, g_sync_bpp, - g_sync_username, g_sync_password, - g_sync_data, g_sync_type, g_sync_domain, - g_sync_program, g_sync_directory, - g_sync_client_ip); - } - else - { - /* g_sync_width is really display */ - g_sync_result = session_reconnect_fork(g_sync_width, g_sync_username); - } - lock_sync_sem_release(); - return 0; + if (g_sync_cmd == 0) + { + g_sync_result = session_start_fork(g_sync_width, g_sync_height, g_sync_bpp, + g_sync_username, g_sync_password, + g_sync_data, g_sync_type, g_sync_domain, + g_sync_program, g_sync_directory, + g_sync_client_ip); + } + else + { + /* g_sync_width is really display */ + g_sync_result = session_reconnect_fork(g_sync_width, g_sync_username); + } + + lock_sync_sem_release(); + return 0; } /******************************************************************************/ int DEFAULT_CC session_kill(int pid) { - struct session_chain* tmp; - struct session_chain* prev; + struct session_chain *tmp; + struct session_chain *prev; - /*THREAD-FIX require chain lock */ - lock_chain_acquire(); + /*THREAD-FIX require chain lock */ + lock_chain_acquire(); - tmp=g_sessions; - prev=0; + tmp = g_sessions; + prev = 0; - while (tmp != 0) - { - if (tmp->item == 0) + while (tmp != 0) { - log_message(LOG_LEVEL_ERROR, "session descriptor for " - "pid %d is null!", pid); - if (prev == 0) - { - /* prev does no exist, so it's the first element - so we set - g_sessions */ - g_sessions = tmp->next; - } - else - { - prev->next = tmp->next; - } - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return SESMAN_SESSION_KILL_NULLITEM; + if (tmp->item == 0) + { + log_message(LOG_LEVEL_ERROR, "session descriptor for " + "pid %d is null!", pid); + + if (prev == 0) + { + /* prev does no exist, so it's the first element - so we set + g_sessions */ + g_sessions = tmp->next; + } + else + { + prev->next = tmp->next; + } + + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return SESMAN_SESSION_KILL_NULLITEM; + } + + if (tmp->item->pid == pid) + { + /* deleting the session */ + log_message(LOG_LEVEL_INFO, "++ terminated session: username %s, display :%d.0, session_pid %d, ip %s", tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->client_ip); + g_free(tmp->item); + + if (prev == 0) + { + /* prev does no exist, so it's the first element - so we set + g_sessions */ + g_sessions = tmp->next; + } + else + { + prev->next = tmp->next; + } + + g_free(tmp); + g_session_count--; + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return SESMAN_SESSION_KILL_OK; + } + + /* go on */ + prev = tmp; + tmp = tmp->next; } - if (tmp->item->pid == pid) - { - /* deleting the session */ - log_message(LOG_LEVEL_INFO, "++ terminated session: username %s, display :%d.0, session_pid %d, ip %s", tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->client_ip); - g_free(tmp->item); - if (prev == 0) - { - /* prev does no exist, so it's the first element - so we set - g_sessions */ - g_sessions = tmp->next; - } - else - { - prev->next = tmp->next; - } - g_free(tmp); - g_session_count--; - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return SESMAN_SESSION_KILL_OK; - } - - /* go on */ - prev = tmp; - tmp=tmp->next; - } - - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return SESMAN_SESSION_KILL_NOTFOUND; + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return SESMAN_SESSION_KILL_NOTFOUND; } /******************************************************************************/ void DEFAULT_CC session_sigkill_all() { - struct session_chain* tmp; + struct session_chain *tmp; - /*THREAD-FIX require chain lock */ - lock_chain_acquire(); + /*THREAD-FIX require chain lock */ + lock_chain_acquire(); - tmp=g_sessions; + tmp = g_sessions; - while (tmp != 0) - { - if (tmp->item == 0) + while (tmp != 0) { - log_message(LOG_LEVEL_ERROR, "found null session " - "descriptor!"); - } - else - { - g_sigterm(tmp->item->pid); + if (tmp->item == 0) + { + log_message(LOG_LEVEL_ERROR, "found null session " + "descriptor!"); + } + else + { + g_sigterm(tmp->item->pid); + } + + /* go on */ + tmp = tmp->next; } - /* go on */ - tmp=tmp->next; - } - - /*THREAD-FIX release chain lock */ - lock_chain_release(); + /*THREAD-FIX release chain lock */ + lock_chain_release(); } /******************************************************************************/ -struct session_item* DEFAULT_CC +struct session_item *DEFAULT_CC session_get_bypid(int pid) { - struct session_chain* tmp; - struct session_item* dummy; + struct session_chain *tmp; + struct session_item *dummy; - dummy = g_malloc(sizeof(struct session_item), 1); - if (0 == dummy) - { - log_message(LOG_LEVEL_ERROR, "internal error", pid); + dummy = g_malloc(sizeof(struct session_item), 1); + + if (0 == dummy) + { + log_message(LOG_LEVEL_ERROR, "internal error", pid); + return 0; + } + + /*THREAD-FIX require chain lock */ + lock_chain_acquire(); + + tmp = g_sessions; + + while (tmp != 0) + { + if (tmp->item == 0) + { + log_message(LOG_LEVEL_ERROR, "session descriptor for " + "pid %d is null!", pid); + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return 0; + } + + if (tmp->item->pid == pid) + { + /*THREAD-FIX release chain lock */ + g_memcpy(dummy, tmp->item, sizeof(struct session_item)); + lock_chain_release(); + /*return tmp->item;*/ + return dummy; + } + + /* go on */ + tmp = tmp->next; + } + + /*THREAD-FIX release chain lock */ + lock_chain_release(); return 0; - } - - /*THREAD-FIX require chain lock */ - lock_chain_acquire(); - - tmp = g_sessions; - while (tmp != 0) - { - if (tmp->item == 0) - { - log_message(LOG_LEVEL_ERROR, "session descriptor for " - "pid %d is null!", pid); - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return 0; - } - - if (tmp->item->pid == pid) - { - /*THREAD-FIX release chain lock */ - g_memcpy(dummy, tmp->item, sizeof(struct session_item)); - lock_chain_release(); - /*return tmp->item;*/ - return dummy; - } - - /* go on */ - tmp=tmp->next; - } - - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return 0; } /******************************************************************************/ -struct SCP_DISCONNECTED_SESSION* -session_get_byuser(char* user, int* cnt, unsigned char flags) +struct SCP_DISCONNECTED_SESSION * +session_get_byuser(char *user, int *cnt, unsigned char flags) { - struct session_chain* tmp; - struct SCP_DISCONNECTED_SESSION* sess; - int count; - int index; + struct session_chain *tmp; + struct SCP_DISCONNECTED_SESSION *sess; + int count; + int index; - count = 0; + count = 0; - /*THREAD-FIX require chain lock */ - lock_chain_acquire(); + /*THREAD-FIX require chain lock */ + lock_chain_acquire(); - tmp = g_sessions; - while (tmp != 0) - { - LOG_DBG("user: %s", user); - if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256))) + tmp = g_sessions; + + while (tmp != 0) { - LOG_DBG("session_get_byuser: status=%d, flags=%d, " - "result=%d", (tmp->item->status), flags, - ((tmp->item->status) & flags)); - if ((tmp->item->status) & flags) - { - count++; - } + LOG_DBG("user: %s", user); + + if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256))) + { + LOG_DBG("session_get_byuser: status=%d, flags=%d, " + "result=%d", (tmp->item->status), flags, + ((tmp->item->status) & flags)); + + if ((tmp->item->status) & flags) + { + count++; + } + } + + /* go on */ + tmp = tmp->next; } - /* go on */ - tmp=tmp->next; - } + if (count == 0) + { + (*cnt) = 0; + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return 0; + } - if (count == 0) - { - (*cnt) = 0; - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return 0; - } + /* malloc() an array of disconnected sessions */ + sess = g_malloc(count *sizeof(struct SCP_DISCONNECTED_SESSION), 1); - /* malloc() an array of disconnected sessions */ - sess=g_malloc(count * sizeof(struct SCP_DISCONNECTED_SESSION),1); - if (sess == 0) - { - (*cnt) = 0; - /*THREAD-FIX release chain lock */ - lock_chain_release(); - return 0; - } + if (sess == 0) + { + (*cnt) = 0; + /*THREAD-FIX release chain lock */ + lock_chain_release(); + return 0; + } - tmp = g_sessions; - index = 0; - while (tmp != 0) - { + tmp = g_sessions; + index = 0; + + while (tmp != 0) + { #warning FIXME: we should get only disconnected sessions! - if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256))) - { - if ((tmp->item->status) & flags) - { - (sess[index]).SID=tmp->item->pid; - (sess[index]).type=tmp->item->type; - (sess[index]).height=tmp->item->height; - (sess[index]).width=tmp->item->width; - (sess[index]).bpp=tmp->item->bpp; + if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256))) + { + if ((tmp->item->status) & flags) + { + (sess[index]).SID = tmp->item->pid; + (sess[index]).type = tmp->item->type; + (sess[index]).height = tmp->item->height; + (sess[index]).width = tmp->item->width; + (sess[index]).bpp = tmp->item->bpp; #warning FIXME: setting idle times and such - /*(sess[index]).connect_time.year = tmp->item->connect_time.year; - (sess[index]).connect_time.month = tmp->item->connect_time.month; - (sess[index]).connect_time.day = tmp->item->connect_time.day; - (sess[index]).connect_time.hour = tmp->item->connect_time.hour; - (sess[index]).connect_time.minute = tmp->item->connect_time.minute; - (sess[index]).disconnect_time.year = tmp->item->disconnect_time.year; - (sess[index]).disconnect_time.month = tmp->item->disconnect_time.month; - (sess[index]).disconnect_time.day = tmp->item->disconnect_time.day; - (sess[index]).disconnect_time.hour = tmp->item->disconnect_time.hour; - (sess[index]).disconnect_time.minute = tmp->item->disconnect_time.minute; - (sess[index]).idle_time.year = tmp->item->idle_time.year; - (sess[index]).idle_time.month = tmp->item->idle_time.month; - (sess[index]).idle_time.day = tmp->item->idle_time.day; - (sess[index]).idle_time.hour = tmp->item->idle_time.hour; - (sess[index]).idle_time.minute = tmp->item->idle_time.minute;*/ - (sess[index]).conn_year = tmp->item->connect_time.year; - (sess[index]).conn_month = tmp->item->connect_time.month; - (sess[index]).conn_day = tmp->item->connect_time.day; - (sess[index]).conn_hour = tmp->item->connect_time.hour; - (sess[index]).conn_minute = tmp->item->connect_time.minute; - (sess[index]).idle_days = tmp->item->idle_time.day; - (sess[index]).idle_hours = tmp->item->idle_time.hour; - (sess[index]).idle_minutes = tmp->item->idle_time.minute; + /*(sess[index]).connect_time.year = tmp->item->connect_time.year; + (sess[index]).connect_time.month = tmp->item->connect_time.month; + (sess[index]).connect_time.day = tmp->item->connect_time.day; + (sess[index]).connect_time.hour = tmp->item->connect_time.hour; + (sess[index]).connect_time.minute = tmp->item->connect_time.minute; + (sess[index]).disconnect_time.year = tmp->item->disconnect_time.year; + (sess[index]).disconnect_time.month = tmp->item->disconnect_time.month; + (sess[index]).disconnect_time.day = tmp->item->disconnect_time.day; + (sess[index]).disconnect_time.hour = tmp->item->disconnect_time.hour; + (sess[index]).disconnect_time.minute = tmp->item->disconnect_time.minute; + (sess[index]).idle_time.year = tmp->item->idle_time.year; + (sess[index]).idle_time.month = tmp->item->idle_time.month; + (sess[index]).idle_time.day = tmp->item->idle_time.day; + (sess[index]).idle_time.hour = tmp->item->idle_time.hour; + (sess[index]).idle_time.minute = tmp->item->idle_time.minute;*/ + (sess[index]).conn_year = tmp->item->connect_time.year; + (sess[index]).conn_month = tmp->item->connect_time.month; + (sess[index]).conn_day = tmp->item->connect_time.day; + (sess[index]).conn_hour = tmp->item->connect_time.hour; + (sess[index]).conn_minute = tmp->item->connect_time.minute; + (sess[index]).idle_days = tmp->item->idle_time.day; + (sess[index]).idle_hours = tmp->item->idle_time.hour; + (sess[index]).idle_minutes = tmp->item->idle_time.minute; - index++; - } + index++; + } + } + + /* go on */ + tmp = tmp->next; } - /* go on */ - tmp=tmp->next; - } - - /*THREAD-FIX release chain lock */ - lock_chain_release(); - (*cnt)=count; - return sess; + /*THREAD-FIX release chain lock */ + lock_chain_release(); + (*cnt) = count; + return sess; } diff --git a/sesman/session.h b/sesman/session.h index a8de90d5..b62b2aee 100644 --- a/sesman/session.h +++ b/sesman/session.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/sessvc/sessvc.c b/sesman/sessvc/sessvc.c index 1ca32b00..2344229c 100644 --- a/sesman/sessvc/sessvc.c +++ b/sesman/sessvc/sessvc.c @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file sessvc.c * @brief Session supervisor * @author Simone Fedele - * + * */ #if defined(HAVE_CONFIG_H) @@ -38,15 +37,15 @@ static int g_term = 0; void DEFAULT_CC term_signal_handler(int sig) { - g_writeln("xrdp-sessvc: term_signal_handler: got signal %d", sig); - g_term = 1; + g_writeln("xrdp-sessvc: term_signal_handler: got signal %d", sig); + g_term = 1; } /*****************************************************************************/ void DEFAULT_CC nil_signal_handler(int sig) { - g_writeln("xrdp-sessvc: nil_signal_handler: got signal %d", sig); + g_writeln("xrdp-sessvc: nil_signal_handler: got signal %d", sig); } /******************************************************************************/ @@ -54,101 +53,115 @@ nil_signal_handler(int sig) int APP_CC chansrv_cleanup(int pid) { - char text[256]; + char text[256]; - g_snprintf(text, 255, "/tmp/.xrdp/xrdp_chansrv_%8.8x_main_term", pid); - if (g_file_exist(text)) - { - g_file_delete(text); - } - g_snprintf(text, 255, "/tmp/.xrdp/xrdp_chansrv_%8.8x_thread_done", pid); - if (g_file_exist(text)) - { - g_file_delete(text); - } - return 0; + g_snprintf(text, 255, "/tmp/.xrdp/xrdp_chansrv_%8.8x_main_term", pid); + + if (g_file_exist(text)) + { + g_file_delete(text); + } + + g_snprintf(text, 255, "/tmp/.xrdp/xrdp_chansrv_%8.8x_thread_done", pid); + + if (g_file_exist(text)) + { + g_file_delete(text); + } + + return 0; } /******************************************************************************/ int DEFAULT_CC -main(int argc, char** argv) +main(int argc, char **argv) { - int ret = 0; - int chansrv_pid = 0; - int wm_pid = 0; - int x_pid = 0; - int lerror = 0; - char exe_path[262]; + int ret = 0; + int chansrv_pid = 0; + int wm_pid = 0; + int x_pid = 0; + int lerror = 0; + char exe_path[262]; - g_init("xrdp-sessvc"); - g_memset(exe_path,0,sizeof(exe_path)); + g_init("xrdp-sessvc"); + g_memset(exe_path, 0, sizeof(exe_path)); - if (argc < 3) - { - g_writeln("xrdp-sessvc: exiting, not enough parameters"); - g_deinit(); - return 1; - } - g_signal_kill(term_signal_handler); /* SIGKILL */ - g_signal_terminate(term_signal_handler); /* SIGTERM */ - g_signal_user_interrupt(term_signal_handler); /* SIGINT */ - g_signal_pipe(nil_signal_handler); /* SIGPIPE */ - x_pid = g_atoi(argv[1]); - wm_pid = g_atoi(argv[2]); - g_writeln("xrdp-sessvc: waiting for X (pid %d) and WM (pid %d)", - x_pid, wm_pid); - /* run xrdp-chansrv as a seperate process */ - chansrv_pid = g_fork(); - if (chansrv_pid == -1) - { - g_writeln("xrdp-sessvc: fork error"); - g_deinit(); - return 1; - } - else if (chansrv_pid == 0) /* child */ - { - g_set_current_dir(XRDP_SBIN_PATH); - g_snprintf(exe_path, 261, "%s/xrdp-chansrv", XRDP_SBIN_PATH); - g_execlp3(exe_path, "xrdp-chansrv", 0); - /* should not get here */ - g_writeln("xrdp-sessvc: g_execlp3() failed"); - g_deinit(); - return 1; - } - lerror = 0; - /* wait for window manager to get done */ - ret = g_waitpid(wm_pid); - while ((ret == 0) && !g_term) - { + if (argc < 3) + { + g_writeln("xrdp-sessvc: exiting, not enough parameters"); + g_deinit(); + return 1; + } + + g_signal_kill(term_signal_handler); /* SIGKILL */ + g_signal_terminate(term_signal_handler); /* SIGTERM */ + g_signal_user_interrupt(term_signal_handler); /* SIGINT */ + g_signal_pipe(nil_signal_handler); /* SIGPIPE */ + x_pid = g_atoi(argv[1]); + wm_pid = g_atoi(argv[2]); + g_writeln("xrdp-sessvc: waiting for X (pid %d) and WM (pid %d)", + x_pid, wm_pid); + /* run xrdp-chansrv as a seperate process */ + chansrv_pid = g_fork(); + + if (chansrv_pid == -1) + { + g_writeln("xrdp-sessvc: fork error"); + g_deinit(); + return 1; + } + else if (chansrv_pid == 0) /* child */ + { + g_set_current_dir(XRDP_SBIN_PATH); + g_snprintf(exe_path, 261, "%s/xrdp-chansrv", XRDP_SBIN_PATH); + g_execlp3(exe_path, "xrdp-chansrv", 0); + /* should not get here */ + g_writeln("xrdp-sessvc: g_execlp3() failed"); + g_deinit(); + return 1; + } + + lerror = 0; + /* wait for window manager to get done */ ret = g_waitpid(wm_pid); - g_sleep(1); - } - if (ret < 0) - { - lerror = g_get_errno(); - } - g_writeln("xrdp-sessvc: WM is dead (waitpid said %d, errno is %d) " - "exiting...", ret, lerror); - /* kill channel server */ - g_writeln("xrdp-sessvc: stopping channel server"); - g_sigterm(chansrv_pid); - ret = g_waitpid(chansrv_pid); - while ((ret == 0) && !g_term) - { + + while ((ret == 0) && !g_term) + { + ret = g_waitpid(wm_pid); + g_sleep(1); + } + + if (ret < 0) + { + lerror = g_get_errno(); + } + + g_writeln("xrdp-sessvc: WM is dead (waitpid said %d, errno is %d) " + "exiting...", ret, lerror); + /* kill channel server */ + g_writeln("xrdp-sessvc: stopping channel server"); + g_sigterm(chansrv_pid); ret = g_waitpid(chansrv_pid); - g_sleep(1); - } - chansrv_cleanup(chansrv_pid); - /* kill X server */ - g_writeln("xrdp-sessvc: stopping X server"); - g_sigterm(x_pid); - ret = g_waitpid(x_pid); - while ((ret == 0) && !g_term) - { + + while ((ret == 0) && !g_term) + { + ret = g_waitpid(chansrv_pid); + g_sleep(1); + } + + chansrv_cleanup(chansrv_pid); + /* kill X server */ + g_writeln("xrdp-sessvc: stopping X server"); + g_sigterm(x_pid); ret = g_waitpid(x_pid); - g_sleep(1); - } - g_writeln("xrdp-sessvc: clean exit"); - g_deinit(); - return 0; + + while ((ret == 0) && !g_term) + { + ret = g_waitpid(x_pid); + g_sleep(1); + } + + g_writeln("xrdp-sessvc: clean exit"); + g_deinit(); + return 0; } diff --git a/sesman/sig.c b/sesman/sig.c index 151c0c57..b8f320f1 100644 --- a/sesman/sig.c +++ b/sesman/sig.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -31,170 +30,176 @@ extern int g_sck; extern int g_pid; -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ extern tbus g_term_event; /******************************************************************************/ void DEFAULT_CC sig_sesman_shutdown(int sig) { - char pid_file[256]; + char pid_file[256]; - log_message(LOG_LEVEL_INFO, "shutting down sesman %d", 1); + log_message(LOG_LEVEL_INFO, "shutting down sesman %d", 1); - if (g_getpid() != g_pid) - { - LOG_DBG("g_getpid() [%d] differs from g_pid [%d]", (g_getpid()), g_pid); - return; - } + if (g_getpid() != g_pid) + { + LOG_DBG("g_getpid() [%d] differs from g_pid [%d]", (g_getpid()), g_pid); + return; + } - LOG_DBG(" - getting signal %d pid %d", sig, g_getpid()); + LOG_DBG(" - getting signal %d pid %d", sig, g_getpid()); - g_set_wait_obj(g_term_event); + g_set_wait_obj(g_term_event); - g_tcp_close(g_sck); + g_tcp_close(g_sck); - session_sigkill_all(); + session_sigkill_all(); - g_snprintf(pid_file, 255, "%s/xrdp-sesman.pid", XRDP_PID_PATH); - g_file_delete(pid_file); + g_snprintf(pid_file, 255, "%s/xrdp-sesman.pid", XRDP_PID_PATH); + g_file_delete(pid_file); } /******************************************************************************/ void DEFAULT_CC sig_sesman_reload_cfg(int sig) { - int error; - struct config_sesman *cfg; - char cfg_file[256]; + int error; + struct config_sesman *cfg; + char cfg_file[256]; - log_message(LOG_LEVEL_WARNING, "receiving SIGHUP %d", 1); + log_message(LOG_LEVEL_WARNING, "receiving SIGHUP %d", 1); - if (g_getpid() != g_pid) - { - LOG_DBG("g_getpid() [%d] differs from g_pid [%d]", g_getpid(), g_pid); - return; - } - - cfg = g_malloc(sizeof(struct config_sesman), 1); - if (0 == cfg) - { - log_message(LOG_LEVEL_ERROR, "error creating new config: - keeping old cfg"); - return; - } - - if (config_read(cfg) != 0) - { - log_message(LOG_LEVEL_ERROR, "error reading config - keeping old cfg"); - return; - } - - /* stop logging subsystem */ - log_end(); - - /* replace old config with new readed one */ - g_cfg = cfg; - - g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); - - /* start again logging subsystem */ - error = log_start(cfg_file,"XRDP-sesman"); - - if (error != LOG_STARTUP_OK) - { - char buf[256]; - switch (error) + if (g_getpid() != g_pid) { - case LOG_ERROR_MALLOC: - g_printf("error on malloc. cannot restart logging. log stops here, sorry.\n"); - break; - case LOG_ERROR_FILE_OPEN: - g_printf("error reopening log file [%s]. log stops here, sorry.\n", getLogFile(buf,255)); - break; + LOG_DBG("g_getpid() [%d] differs from g_pid [%d]", g_getpid(), g_pid); + return; } - } - log_message(LOG_LEVEL_INFO, "configuration reloaded, log subsystem restarted"); + cfg = g_malloc(sizeof(struct config_sesman), 1); + + if (0 == cfg) + { + log_message(LOG_LEVEL_ERROR, "error creating new config: - keeping old cfg"); + return; + } + + if (config_read(cfg) != 0) + { + log_message(LOG_LEVEL_ERROR, "error reading config - keeping old cfg"); + return; + } + + /* stop logging subsystem */ + log_end(); + + /* replace old config with new readed one */ + g_cfg = cfg; + + g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); + + /* start again logging subsystem */ + error = log_start(cfg_file, "XRDP-sesman"); + + if (error != LOG_STARTUP_OK) + { + char buf[256]; + + switch (error) + { + case LOG_ERROR_MALLOC: + g_printf("error on malloc. cannot restart logging. log stops here, sorry.\n"); + break; + case LOG_ERROR_FILE_OPEN: + g_printf("error reopening log file [%s]. log stops here, sorry.\n", getLogFile(buf, 255)); + break; + } + } + + log_message(LOG_LEVEL_INFO, "configuration reloaded, log subsystem restarted"); } /******************************************************************************/ void DEFAULT_CC sig_sesman_session_end(int sig) { - int pid; + int pid; - if (g_getpid() != g_pid) - { - return; - } - pid = g_waitchild(); - if (pid > 0) - { - session_kill(pid); - } + if (g_getpid() != g_pid) + { + return; + } + + pid = g_waitchild(); + + if (pid > 0) + { + session_kill(pid); + } } /******************************************************************************/ -void* DEFAULT_CC -sig_handler_thread(void* arg) +void *DEFAULT_CC +sig_handler_thread(void *arg) { - int recv_signal; - sigset_t sigmask; - sigset_t oldmask; - sigset_t waitmask; + int recv_signal; + sigset_t sigmask; + sigset_t oldmask; + sigset_t waitmask; - /* mask signals to be able to wait for them... */ - sigfillset(&sigmask); - /* it is a good idea not to block SIGILL SIGSEGV */ - /* SIGFPE -- see sigaction(2) NOTES */ - pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); + /* mask signals to be able to wait for them... */ + sigfillset(&sigmask); + /* it is a good idea not to block SIGILL SIGSEGV */ + /* SIGFPE -- see sigaction(2) NOTES */ + pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); - /* building the signal wait mask... */ - sigemptyset(&waitmask); - sigaddset(&waitmask, SIGHUP); - sigaddset(&waitmask, SIGCHLD); - sigaddset(&waitmask, SIGTERM); - sigaddset(&waitmask, SIGKILL); - sigaddset(&waitmask, SIGINT); + /* building the signal wait mask... */ + sigemptyset(&waitmask); + sigaddset(&waitmask, SIGHUP); + sigaddset(&waitmask, SIGCHLD); + sigaddset(&waitmask, SIGTERM); + sigaddset(&waitmask, SIGKILL); + sigaddset(&waitmask, SIGINT); -// sigaddset(&waitmask, SIGFPE); -// sigaddset(&waitmask, SIGILL); -// sigaddset(&waitmask, SIGSEGV); + // sigaddset(&waitmask, SIGFPE); + // sigaddset(&waitmask, SIGILL); + // sigaddset(&waitmask, SIGSEGV); - do - { - LOG_DBG(&(g_cfg->log), "calling sigwait()",0); - sigwait(&waitmask, &recv_signal); - switch (recv_signal) + do { - case SIGHUP: - //reload cfg - //we must stop & restart logging, or copy logging cfg!!!! - LOG_DBG("sesman received SIGHUP", 0); - //return 0; - break; - case SIGCHLD: - /* a session died */ - LOG_DBG("sesman received SIGCHLD", 0); - sig_sesman_session_end(SIGCHLD); - break; - case SIGINT: - /* we die */ - LOG_DBG("sesman received SIGINT", 0); - sig_sesman_shutdown(recv_signal); - break; - case SIGKILL: - /* we die */ - LOG_DBG("sesman received SIGKILL", 0); - sig_sesman_shutdown(recv_signal); - break; - case SIGTERM: - /* we die */ - LOG_DBG("sesman received SIGTERM", 0); - sig_sesman_shutdown(recv_signal); - break; - } - } while (1); + LOG_DBG(&(g_cfg->log), "calling sigwait()", 0); + sigwait(&waitmask, &recv_signal); - return 0; + switch (recv_signal) + { + case SIGHUP: + //reload cfg + //we must stop & restart logging, or copy logging cfg!!!! + LOG_DBG("sesman received SIGHUP", 0); + //return 0; + break; + case SIGCHLD: + /* a session died */ + LOG_DBG("sesman received SIGCHLD", 0); + sig_sesman_session_end(SIGCHLD); + break; + case SIGINT: + /* we die */ + LOG_DBG("sesman received SIGINT", 0); + sig_sesman_shutdown(recv_signal); + break; + case SIGKILL: + /* we die */ + LOG_DBG("sesman received SIGKILL", 0); + sig_sesman_shutdown(recv_signal); + break; + case SIGTERM: + /* we die */ + LOG_DBG("sesman received SIGTERM", 0); + sig_sesman_shutdown(recv_signal); + break; + } + } + while (1); + + return 0; } diff --git a/sesman/sig.h b/sesman/sig.h index 7c6d2bfe..ac648da0 100644 --- a/sesman/sig.h +++ b/sesman/sig.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -64,4 +63,3 @@ void* DEFAULT_CC sig_handler_thread(void* arg); #endif - diff --git a/sesman/thread.c b/sesman/thread.c index 98a92533..a33b93d9 100644 --- a/sesman/thread.c +++ b/sesman/thread.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -31,7 +30,7 @@ #include #include -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ static pthread_t g_thread_sighandler; //static pthread_t g_thread_updater; @@ -43,53 +42,53 @@ int g_thread_sck; int DEFAULT_CC thread_sighandler_start(void) { - int ret; - sigset_t sigmask; - sigset_t oldmask; - sigset_t waitmask; + int ret; + sigset_t sigmask; + sigset_t oldmask; + sigset_t waitmask; - /* mask signals to be able to wait for them... */ - sigfillset(&sigmask); - pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); + /* mask signals to be able to wait for them... */ + sigfillset(&sigmask); + pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); - /* unblock some signals... */ - sigemptyset(&waitmask); + /* unblock some signals... */ + sigemptyset(&waitmask); - /* it is a good idea not to block SIGILL SIGSEGV */ - /* SIGFPE -- see sigaction(2) NOTES */ - sigaddset(&waitmask, SIGILL); - sigaddset(&waitmask, SIGSEGV); - sigaddset(&waitmask, SIGFPE); - pthread_sigmask(SIG_UNBLOCK, &waitmask, NULL); + /* it is a good idea not to block SIGILL SIGSEGV */ + /* SIGFPE -- see sigaction(2) NOTES */ + sigaddset(&waitmask, SIGILL); + sigaddset(&waitmask, SIGSEGV); + sigaddset(&waitmask, SIGFPE); + pthread_sigmask(SIG_UNBLOCK, &waitmask, NULL); - log_message(LOG_LEVEL_INFO,"starting signal handling thread..."); + log_message(LOG_LEVEL_INFO, "starting signal handling thread..."); - ret = pthread_create(&g_thread_sighandler, NULL, sig_handler_thread, ""); - pthread_detach(g_thread_sighandler); + ret = pthread_create(&g_thread_sighandler, NULL, sig_handler_thread, ""); + pthread_detach(g_thread_sighandler); - if (ret == 0) - { - log_message(LOG_LEVEL_INFO, "signal handler thread started successfully"); - return 0; - } + if (ret == 0) + { + log_message(LOG_LEVEL_INFO, "signal handler thread started successfully"); + return 0; + } - /* if something happened while starting a new thread... */ - switch (ret) - { - case EINVAL: - log_message(LOG_LEVEL_ERROR, "invalid attributes for signal handling thread (creation returned EINVAL)"); - break; - case EAGAIN: - log_message(LOG_LEVEL_ERROR, "not enough resources to start signal handling thread (creation returned EAGAIN)"); - break; - case EPERM: - log_message(LOG_LEVEL_ERROR, "invalid permissions for signal handling thread (creation returned EPERM)"); - break; - default: - log_message(LOG_LEVEL_ERROR, "unknown error starting signal handling thread"); - } + /* if something happened while starting a new thread... */ + switch (ret) + { + case EINVAL: + log_message(LOG_LEVEL_ERROR, "invalid attributes for signal handling thread (creation returned EINVAL)"); + break; + case EAGAIN: + log_message(LOG_LEVEL_ERROR, "not enough resources to start signal handling thread (creation returned EAGAIN)"); + break; + case EPERM: + log_message(LOG_LEVEL_ERROR, "invalid permissions for signal handling thread (creation returned EPERM)"); + break; + default: + log_message(LOG_LEVEL_ERROR, "unknown error starting signal handling thread"); + } - return 1; + return 1; } #ifdef JUST_TO_AVOID_COMPILER_ERRORS @@ -97,38 +96,38 @@ thread_sighandler_start(void) int DEFAULT_CC thread_session_update_start(void) { - int ret; - //starts the session update thread - //that checks for idle time, destroys sessions, ecc... + int ret; + //starts the session update thread + //that checks for idle time, destroys sessions, ecc... #warning this thread should always request lock_fork before read or write #warning (so we can Fork() In Peace) - ret = pthread_create(&g_thread_updater, NULL, , ""); - pthread_detach(g_thread_updater); + ret = pthread_create(&g_thread_updater, NULL, , ""); + pthread_detach(g_thread_updater); - if (ret == 0) - { - log_message(&(g_cfg->log), LOG_LEVEL_INFO, "session update thread started successfully"); - return 0; - } + if (ret == 0) + { + log_message(&(g_cfg->log), LOG_LEVEL_INFO, "session update thread started successfully"); + return 0; + } - /* if something happened while starting a new thread... */ - switch (ret) - { - case EINVAL: - log_message(LOG_LEVEL_ERROR, "invalid attributes for session update thread (creation returned EINVAL)"); - break; - case EAGAIN: - log_message(LOG_LEVEL_ERROR, "not enough resources to start session update thread (creation returned EAGAIN)"); - break; - case EPERM: - log_message(LOG_LEVEL_ERROR, "invalid permissions for session update thread (creation returned EPERM)"); - break; - default: - log_message(LOG_LEVEL_ERROR, "unknown error starting session update thread"); - } + /* if something happened while starting a new thread... */ + switch (ret) + { + case EINVAL: + log_message(LOG_LEVEL_ERROR, "invalid attributes for session update thread (creation returned EINVAL)"); + break; + case EAGAIN: + log_message(LOG_LEVEL_ERROR, "not enough resources to start session update thread (creation returned EAGAIN)"); + break; + case EPERM: + log_message(LOG_LEVEL_ERROR, "invalid permissions for session update thread (creation returned EPERM)"); + break; + default: + log_message(LOG_LEVEL_ERROR, "unknown error starting session update thread"); + } - return 1; + return 1; } #endif @@ -136,39 +135,39 @@ thread_session_update_start(void) int DEFAULT_CC thread_scp_start(int skt) { - int ret; - pthread_t th; + int ret; + pthread_t th; - /* blocking the use of thread_skt */ - lock_socket_acquire(); - g_thread_sck = skt; + /* blocking the use of thread_skt */ + lock_socket_acquire(); + g_thread_sck = skt; - /* start a thread that processes a connection */ - ret = pthread_create(&th, NULL, scp_process_start, ""); - //ret = pthread_create(&th, NULL, scp_process_start, (void*) (&g_thread_sck)); - pthread_detach(th); + /* start a thread that processes a connection */ + ret = pthread_create(&th, NULL, scp_process_start, ""); + //ret = pthread_create(&th, NULL, scp_process_start, (void*) (&g_thread_sck)); + pthread_detach(th); - if (ret == 0) - { - log_message(LOG_LEVEL_INFO, "scp thread on sck %d started successfully", skt); - return 0; - } + if (ret == 0) + { + log_message(LOG_LEVEL_INFO, "scp thread on sck %d started successfully", skt); + return 0; + } - /* if something happened while starting a new thread... */ - switch (ret) - { - case EINVAL: - log_message(LOG_LEVEL_ERROR, "invalid attributes for scp thread on sck %d (creation returned EINVAL)", skt); - break; - case EAGAIN: - log_message(LOG_LEVEL_ERROR, "not enough resources to start scp thread on sck %d (creation returned EAGAIN)", skt); - break; - case EPERM: - log_message(LOG_LEVEL_ERROR, "invalid permissions for scp thread on sck %d (creation returned EPERM)", skt); - break; - default: - log_message(LOG_LEVEL_ERROR, "unknown error starting scp thread on sck %d"); - } + /* if something happened while starting a new thread... */ + switch (ret) + { + case EINVAL: + log_message(LOG_LEVEL_ERROR, "invalid attributes for scp thread on sck %d (creation returned EINVAL)", skt); + break; + case EAGAIN: + log_message(LOG_LEVEL_ERROR, "not enough resources to start scp thread on sck %d (creation returned EAGAIN)", skt); + break; + case EPERM: + log_message(LOG_LEVEL_ERROR, "invalid permissions for scp thread on sck %d (creation returned EPERM)", skt); + break; + default: + log_message(LOG_LEVEL_ERROR, "unknown error starting scp thread on sck %d"); + } - return 1; + return 1; } diff --git a/sesman/thread.h b/sesman/thread.h index b3c12258..9dcb53b4 100644 --- a/sesman/thread.h +++ b/sesman/thread.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/tools/dis.c b/sesman/tools/dis.c index 0dbc74d8..52400847 100644 --- a/sesman/tools/dis.c +++ b/sesman/tools/dis.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2011 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include @@ -24,42 +23,48 @@ #include #include -int main(int argc, char** argv) +int main(int argc, char **argv) { - int sck; - int dis; - struct sockaddr_un sa; - size_t len; - char* p; - char* display; + int sck; + int dis; + struct sockaddr_un sa; + size_t len; + char *p; + char *display; + + if (argc != 1) + { + printf("xrdp disconnect utility\n"); + printf("run with no parameters to disconnect you xrdp session\n"); + return 0; + } + + display = getenv("DISPLAY"); + + if (display == 0) + { + printf("display not set\n"); + return 1; + } + + dis = strtol(display + 1, &p, 10); + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + sprintf(sa.sun_path, "/tmp/.xrdp/xrdp_disconnect_display_%d", dis); + + if (access(sa.sun_path, F_OK) != 0) + { + printf("not in an xrdp session\n"); + return 1; + } + + sck = socket(PF_UNIX, SOCK_DGRAM, 0); + len = sizeof(sa); + + if (sendto(sck, "sig", 4, 0, (struct sockaddr *)&sa, len) > 0) + { + printf("message sent ok\n"); + } - if (argc != 1) - { - printf("xrdp disconnect utility\n"); - printf("run with no parameters to disconnect you xrdp session\n"); return 0; - } - - display = getenv("DISPLAY"); - if (display == 0) - { - printf("display not set\n"); - return 1; - } - dis = strtol(display + 1, &p, 10); - memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_UNIX; - sprintf(sa.sun_path, "/tmp/.xrdp/xrdp_disconnect_display_%d", dis); - if (access(sa.sun_path, F_OK) != 0) - { - printf("not in an xrdp session\n"); - return 1; - } - sck = socket(PF_UNIX, SOCK_DGRAM, 0); - len = sizeof(sa); - if (sendto(sck, "sig", 4, 0, (struct sockaddr*)&sa, len) > 0) - { - printf("message sent ok\n"); - } - return 0; } diff --git a/sesman/tools/sesadmin.c b/sesman/tools/sesadmin.c index 22f20c23..25af850b 100644 --- a/sesman/tools/sesadmin.c +++ b/sesman/tools/sesadmin.c @@ -22,174 +22,176 @@ char port[257]; struct log_config logging; -void cmndList(struct SCP_CONNECTION* c); -void cmndKill(struct SCP_CONNECTION* c, struct SCP_SESSION* s); +void cmndList(struct SCP_CONNECTION *c); +void cmndKill(struct SCP_CONNECTION *c, struct SCP_SESSION *s); void cmndHelp(); -int inputSession(struct SCP_SESSION* s); +int inputSession(struct SCP_SESSION *s); unsigned int menuSelect(unsigned int choices); -int main(int argc, char** argv) +int main(int argc, char **argv) { - struct SCP_SESSION* s; - struct SCP_CONNECTION* c; - enum SCP_CLIENT_STATES_E e; - //int end; - int idx; - //int sel; - int sock; - char* pwd; + struct SCP_SESSION *s; + struct SCP_CONNECTION *c; + enum SCP_CLIENT_STATES_E e; + //int end; + int idx; + //int sel; + int sock; + char *pwd; - user[0]='\0'; - pass[0]='\0'; - cmnd[0]='\0'; - serv[0]='\0'; - port[0]='\0'; + user[0] = '\0'; + pass[0] = '\0'; + cmnd[0] = '\0'; + serv[0] = '\0'; + port[0] = '\0'; - logging.program_name = g_strdup("sesadmin"); - logging.log_file = g_strdup("xrdp-sesadmin.log"); - logging.log_level = LOG_LEVEL_DEBUG; - logging.enable_syslog = 0; - log_start_from_param(&logging); + logging.program_name = g_strdup("sesadmin"); + logging.log_file = g_strdup("xrdp-sesadmin.log"); + logging.log_level = LOG_LEVEL_DEBUG; + logging.enable_syslog = 0; + log_start_from_param(&logging); - for (idx = 0; idx < argc; idx++) - { - if (0 == g_strncmp(argv[idx], "-u=", 3)) + for (idx = 0; idx < argc; idx++) { - g_strncpy(user, (argv[idx])+3, 256); + if (0 == g_strncmp(argv[idx], "-u=", 3)) + { + g_strncpy(user, (argv[idx]) + 3, 256); + } + else if (0 == g_strncmp(argv[idx], "-p=", 3)) + { + g_strncpy(pass, (argv[idx]) + 3, 256); + } + else if (0 == g_strncmp(argv[idx], "-s=", 3)) + { + g_strncpy(serv, (argv[idx]) + 3, 256); + } + else if (0 == g_strncmp(argv[idx], "-i=", 3)) + { + g_strncpy(port, (argv[idx]) + 3, 256); + } + else if (0 == g_strncmp(argv[idx], "-c=", 3)) + { + g_strncpy(cmnd, (argv[idx]) + 3, 256); + } } - else if (0 == g_strncmp(argv[idx], "-p=", 3)) + + if (0 == g_strncmp(serv, "", 1)) { - g_strncpy(pass, (argv[idx])+3, 256); + g_strncpy(serv, "localhost", 256); } - else if (0 == g_strncmp(argv[idx], "-s=", 3)) + + if (0 == g_strncmp(port, "", 1)) { - g_strncpy(serv, (argv[idx])+3, 256); + g_strncpy(port, "3350", 256); } - else if (0 == g_strncmp(argv[idx], "-i=", 3)) + + if (0 == g_strncmp(user, "", 1)) { - g_strncpy(port, (argv[idx])+3, 256); + g_strncpy(user, "root", 256); } - else if (0 == g_strncmp(argv[idx], "-c=", 3)) + + if (0 == g_strncmp(pass, "", 1)) { - g_strncpy(cmnd, (argv[idx])+3, 256); + pwd = getpass("password:"); + g_strncpy(pass, pwd, 256); + + /* zeroing the password */ + while ((*pwd) != '\0') + { + (*pwd) = 0x00; + pwd++; + } } - } - if (0 == g_strncmp(serv, "", 1)) - { - g_strncpy(serv, "localhost", 256); - } + scp_init(&logging); - if (0 == g_strncmp(port, "", 1)) - { - g_strncpy(port, "3350", 256); - } + sock = g_tcp_socket(); + s = scp_session_create(); + c = scp_connection_create(sock); - if (0 == g_strncmp(user, "", 1)) - { - g_strncpy(user, "root", 256); - } + LOG_DBG("Connecting to %s:%s with user %s (%s)\n", serv, port, user, pass); - if (0 == g_strncmp(pass, "", 1)) - { - pwd = getpass("password:"); - g_strncpy(pass, pwd, 256); - - /* zeroing the password */ - while ((*pwd) != '\0') + if (0 != g_tcp_connect(sock, serv, port)) { - (*pwd) = 0x00; - pwd++; + LOG_DBG("g_tcp_connect() error\n"); + return 1; } - } - scp_init(&logging); + scp_session_set_type(s, SCP_SESSION_TYPE_MANAGE); + scp_session_set_version(s, 1); + scp_session_set_username(s, user); + scp_session_set_password(s, pass); - sock = g_tcp_socket(); - s = scp_session_create(); - c = scp_connection_create(sock); + e = scp_v1c_mng_connect(c, s); - LOG_DBG("Connecting to %s:%s with user %s (%s)\n", serv, port, user, pass); + if (SCP_CLIENT_STATE_OK != e) + { + LOG_DBG("libscp error connecting: %s %d\n", s->errstr, (int)e); + } - if (0 != g_tcp_connect(sock, serv, port)) - { - LOG_DBG("g_tcp_connect() error\n"); - return 1; - } + if (0 == g_strncmp(cmnd, "list", 5)) + { + cmndList(c); + } + else if (0 == g_strncmp(cmnd, "kill:", 5)) + { + cmndKill(c, s); + } - scp_session_set_type(s, SCP_SESSION_TYPE_MANAGE); - scp_session_set_version(s, 1); - scp_session_set_username(s, user); - scp_session_set_password(s, pass); + g_tcp_close(sock); + scp_session_destroy(s); + scp_connection_destroy(c); + log_end(); - e = scp_v1c_mng_connect(c,s); - - if (SCP_CLIENT_STATE_OK != e) - { - LOG_DBG("libscp error connecting: %s %d\n", s->errstr, (int)e); - } - - if (0 == g_strncmp(cmnd, "list", 5)) - { - cmndList(c); - } - else if (0 == g_strncmp(cmnd, "kill:", 5)) - { - cmndKill(c,s); - } - - g_tcp_close(sock); - scp_session_destroy(s); - scp_connection_destroy(c); - log_end(); - - return 0; + return 0; } void cmndHelp() { - fprintf(stderr, "sesadmin - a console sesman adminitration tool\n"); - fprintf(stderr, "sysntax: sesadmin [] COMMAND [OPTIONS]\n\n"); - fprintf(stderr, "-u=: username to connect to sesman [MANDATORY]\n"); - fprintf(stderr, "-p=: password to connect to sesman [MANDATORY]\n"); - fprintf(stderr, "-s=: sesman host (default is localhost)\n"); - fprintf(stderr, "-i= : sesman port (default 3350)\n"); - fprintf(stderr, "-c= : command to execute on the server [MANDATORY]\n"); - fprintf(stderr, " it can be one of those:\n"); - fprintf(stderr, " LIST\n"); - fprintf(stderr, " KILL:\n"); + fprintf(stderr, "sesadmin - a console sesman adminitration tool\n"); + fprintf(stderr, "sysntax: sesadmin [] COMMAND [OPTIONS]\n\n"); + fprintf(stderr, "-u=: username to connect to sesman [MANDATORY]\n"); + fprintf(stderr, "-p=: password to connect to sesman [MANDATORY]\n"); + fprintf(stderr, "-s=: sesman host (default is localhost)\n"); + fprintf(stderr, "-i= : sesman port (default 3350)\n"); + fprintf(stderr, "-c= : command to execute on the server [MANDATORY]\n"); + fprintf(stderr, " it can be one of those:\n"); + fprintf(stderr, " LIST\n"); + fprintf(stderr, " KILL:\n"); } -void cmndList(struct SCP_CONNECTION* c) +void cmndList(struct SCP_CONNECTION *c) { - struct SCP_DISCONNECTED_SESSION* dsl; - enum SCP_CLIENT_STATES_E e; - int scnt; - int idx; + struct SCP_DISCONNECTED_SESSION *dsl; + enum SCP_CLIENT_STATES_E e; + int scnt; + int idx; - e = scp_v1c_mng_get_session_list(c, &scnt, &dsl); - if ((SCP_CLIENT_STATE_LIST_OK == e) && (scnt > 0)) - { - for (idx = 0; idx < scnt; idx++) + e = scp_v1c_mng_get_session_list(c, &scnt, &dsl); + + if ((SCP_CLIENT_STATE_LIST_OK == e) && (scnt > 0)) { - printf("%d\t%d\t%dx%dx%d\t%d-%d-%d\t%04d/%02d/%02d@%02d:%02d\n", \ - (dsl[idx]).SID, (dsl[idx]).type, (dsl[idx]).width, (dsl[idx]).height, (dsl[idx]).bpp, \ - (dsl[idx]).idle_days, (dsl[idx]).idle_hours, (dsl[idx]).idle_minutes, \ - (dsl[idx]).conn_year, (dsl[idx]).conn_month, (dsl[idx]).conn_day, (dsl[idx]).conn_hour, (dsl[idx]).conn_minute); + for (idx = 0; idx < scnt; idx++) + { + printf("%d\t%d\t%dx%dx%d\t%d-%d-%d\t%04d/%02d/%02d@%02d:%02d\n", \ + (dsl[idx]).SID, (dsl[idx]).type, (dsl[idx]).width, (dsl[idx]).height, (dsl[idx]).bpp, \ + (dsl[idx]).idle_days, (dsl[idx]).idle_hours, (dsl[idx]).idle_minutes, \ + (dsl[idx]).conn_year, (dsl[idx]).conn_month, (dsl[idx]).conn_day, (dsl[idx]).conn_hour, (dsl[idx]).conn_minute); + } + + if (0 != dsl) + { + g_free(dsl); + } } - if (0 != dsl) + else { - g_free(dsl); + printf("No sessions.\n"); } - } - else - { - printf("No sessions.\n"); - } } -void cmndKill(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +void cmndKill(struct SCP_CONNECTION *c, struct SCP_SESSION *s) { } diff --git a/sesman/tools/sesrun.c b/sesman/tools/sesrun.c index f22e5a30..5ad3b5cc 100644 --- a/sesman/tools/sesrun.c +++ b/sesman/tools/sesrun.c @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file sesrun.c * @brief An utility to start a session * @author Jay Sorg, Simone Fedele - * + * */ #include "sesman.h" @@ -34,93 +33,100 @@ struct config_sesman g_cfg; /* config.h */ /******************************************************************************/ int DEFAULT_CC -main(int argc, char** argv) +main(int argc, char **argv) { - int sck; - int code; - int i; - int size; - int version; - int width; - int height; - int bpp; - int display; - struct stream* in_s; - struct stream* out_s; - char* username; - char* password; - long data; + int sck; + int code; + int i; + int size; + int version; + int width; + int height; + int bpp; + int display; + struct stream *in_s; + struct stream *out_s; + char *username; + char *password; + long data; - if (0 != config_read(&g_cfg)) - { - g_printf("sesrun: error reading config. quitting.\n"); - return 1; - } - - g_pid = g_getpid(); - if (argc == 1) - { - g_printf("xrdp session starter v0.1\n"); - g_printf("\nusage:\n"); - g_printf("sesrun \n"); - } - else if (argc == 7) - { - username = argv[2]; - password = argv[3]; - width = g_atoi(argv[4]); - height = g_atoi(argv[5]); - bpp = g_atoi(argv[6]); - make_stream(in_s); - init_stream(in_s, 8192); - make_stream(out_s); - init_stream(out_s, 8192); - sck = g_tcp_socket(); - if (g_tcp_connect(sck, argv[1], g_cfg.listen_port) == 0) + if (0 != config_read(&g_cfg)) { - s_push_layer(out_s, channel_hdr, 8); - out_uint16_be(out_s, 0); /* code */ - i = g_strlen(username); - out_uint16_be(out_s, i); - out_uint8a(out_s, username, i); - i = g_strlen(password); - out_uint16_be(out_s, i); - out_uint8a(out_s, password, i); - out_uint16_be(out_s, width); - out_uint16_be(out_s, height); - out_uint16_be(out_s, bpp); - s_mark_end(out_s); - s_pop_layer(out_s, channel_hdr); - out_uint32_be(out_s, 0); /* version */ - out_uint32_be(out_s, out_s->end - out_s->data); /* size */ - tcp_force_send(sck, out_s->data, out_s->end - out_s->data); - if (tcp_force_recv(sck, in_s->data, 8) == 0) - { - in_uint32_be(in_s, version); - in_uint32_be(in_s, size); + g_printf("sesrun: error reading config. quitting.\n"); + return 1; + } + + g_pid = g_getpid(); + + if (argc == 1) + { + g_printf("xrdp session starter v0.1\n"); + g_printf("\nusage:\n"); + g_printf("sesrun \n"); + } + else if (argc == 7) + { + username = argv[2]; + password = argv[3]; + width = g_atoi(argv[4]); + height = g_atoi(argv[5]); + bpp = g_atoi(argv[6]); + make_stream(in_s); init_stream(in_s, 8192); - if (tcp_force_recv(sck, in_s->data, size - 8) == 0) + make_stream(out_s); + init_stream(out_s, 8192); + sck = g_tcp_socket(); + + if (g_tcp_connect(sck, argv[1], g_cfg.listen_port) == 0) { - if (version == 0) - { - in_uint16_be(in_s, code); - if (code == 3) + s_push_layer(out_s, channel_hdr, 8); + out_uint16_be(out_s, 0); /* code */ + i = g_strlen(username); + out_uint16_be(out_s, i); + out_uint8a(out_s, username, i); + i = g_strlen(password); + out_uint16_be(out_s, i); + out_uint8a(out_s, password, i); + out_uint16_be(out_s, width); + out_uint16_be(out_s, height); + out_uint16_be(out_s, bpp); + s_mark_end(out_s); + s_pop_layer(out_s, channel_hdr); + out_uint32_be(out_s, 0); /* version */ + out_uint32_be(out_s, out_s->end - out_s->data); /* size */ + tcp_force_send(sck, out_s->data, out_s->end - out_s->data); + + if (tcp_force_recv(sck, in_s->data, 8) == 0) { - in_uint16_be(in_s, data); - in_uint16_be(in_s, display); - g_printf("ok %d display %d\n", data, display); + in_uint32_be(in_s, version); + in_uint32_be(in_s, size); + init_stream(in_s, 8192); + + if (tcp_force_recv(sck, in_s->data, size - 8) == 0) + { + if (version == 0) + { + in_uint16_be(in_s, code); + + if (code == 3) + { + in_uint16_be(in_s, data); + in_uint16_be(in_s, display); + g_printf("ok %d display %d\n", data, display); + } + } + } } - } } - } + else + { + g_printf("connect error\n"); + } + + g_tcp_close(sck); + free_stream(in_s); + free_stream(out_s); } - else - { - g_printf("connect error\n"); - } - g_tcp_close(sck); - free_stream(in_s); - free_stream(out_s); - } - return 0; + + return 0; } diff --git a/sesman/tools/sestest.c b/sesman/tools/sestest.c index c0784ba3..f2823eb6 100644 --- a/sesman/tools/sestest.c +++ b/sesman/tools/sestest.c @@ -12,205 +12,217 @@ #include -int inputSession(struct SCP_SESSION* s); +int inputSession(struct SCP_SESSION *s); unsigned int menuSelect(unsigned int choices); -int main(int argc, char** argv) +int main(int argc, char **argv) { - char buf[256]; - struct SCP_SESSION* s; - struct SCP_CONNECTION* c; - /*struct SCP_DISCONNECTED_SESSION ds;*/ - struct SCP_DISCONNECTED_SESSION* dsl; - enum SCP_CLIENT_STATES_E e; - struct log_config log; - int end; - int scnt; - int idx; - int sel; - int sock; + char buf[256]; + struct SCP_SESSION *s; + struct SCP_CONNECTION *c; + /*struct SCP_DISCONNECTED_SESSION ds;*/ + struct SCP_DISCONNECTED_SESSION *dsl; + enum SCP_CLIENT_STATES_E e; + struct log_config log; + int end; + int scnt; + int idx; + int sel; + int sock; - log.enable_syslog=0; - log.log_level=99; - log.program_name=g_strdup("sestest"); - log.log_file=g_strdup("sestest.log"); - log_start_from_param(&log); - scp_init(&log); + log.enable_syslog = 0; + log.log_level = 99; + log.program_name = g_strdup("sestest"); + log.log_file = g_strdup("sestest.log"); + log_start_from_param(&log); + scp_init(&log); - sock=g_tcp_socket(); - s = scp_session_create(); - c = scp_connection_create(sock); + sock = g_tcp_socket(); + s = scp_session_create(); + c = scp_connection_create(sock); - if (0!=g_tcp_connect(sock, "localhost", "3350")) - { - g_printf("error connecting"); - return 1; - } - - g_printf("001 - send connect request\n"); - - scp_session_set_type(s, SCP_SESSION_TYPE_XVNC); - scp_session_set_version(s, 1); - scp_session_set_height(s, 600); - scp_session_set_width(s, 800); - scp_session_set_bpp(s, 16); - scp_session_set_rsr(s, 0); - scp_session_set_locale(s, "it_IT"); - scp_session_set_username(s, "prog"); - scp_session_set_password(s, "prog"); - scp_session_set_hostname(s, "odin"); -// scp_session_set_addr(s, SCP_ADDRESS_TYPE_IPV4, "127.0.0.1"); -// scp_session_set_display(struct SCP_SESSION* s, SCP_DISPLAY display); -// scp_session_set_errstr(struct SCP_SESSION* s, char* str); - - /*s.type=SCP_SESSION_TYPE_XVNC; - s.version=1; - s.height=600; - s.width=800; - s.bpp=8; - s.rsr=0; - g_strncpy(s.locale,"it_IT 0123456789",18); - s.username=g_malloc(256, 1); - g_strncpy(s.username,"prog",255); - s.password=g_malloc(256,1); - g_strncpy(s.password, "prog", 255); - g_printf("%s - %s\n", s.username, s.password); - s.hostname=g_malloc(256,1); - g_strncpy(s.hostname, "odin", 255); - s.addr_type=SCP_ADDRESS_TYPE_IPV4; - s.ipv4addr=0; - s.errstr=0;*/ - - end=0; - e=scp_v1c_connect(c,s); - - while (!end) - { - switch (e) + if (0 != g_tcp_connect(sock, "localhost", "3350")) { - case SCP_CLIENT_STATE_OK: - g_printf("OK : display is %d\n", (short int)s->display); - end=1; - break; - case SCP_CLIENT_STATE_SESSION_LIST: - g_printf("OK : session list needed\n"); - e=scp_v1c_get_session_list(c, &scnt, &dsl); - break; - case SCP_CLIENT_STATE_LIST_OK: - g_printf("OK : selecting a session:\n"); - for (idx=0; idx errstr); - g_printf(" username:"); - if (scanf("%255s", buf) < 0) - { - g_writeln("error"); - } - scp_session_set_username(s, buf); - g_printf(" password:"); - if (scanf("%255s", buf) < 0) - { - g_writeln("error"); - } - scp_session_set_password(s, buf); - e=scp_v1c_resend_credentials(c,s); - break; - case SCP_CLIENT_STATE_CONNECTION_DENIED: - g_printf("ERR: connection denied: %s\n", s->errstr); - end=1; - break; - case SCP_CLIENT_STATE_PWD_CHANGE_REQ: - g_printf("OK : password change required\n"); - break; - /*case SCP_CLIENT_STATE_RECONNECT_SINGLE: - g_printf("OK : reconnect to 1 disconnected session\n"); - e=scp_v1c_retrieve_session(&c, &s, &ds); - g_printf("Session Type: %d on %d\n", ds.type, s.display); - g_printf("Session Screen: %dx%dx%d\n", ds.height, ds.width, ds.bpp);*/ - break; - default: - g_printf("protocol error: %d\n", e); - end=1; + g_printf("error connecting"); + return 1; } - } - g_tcp_close(sock); - scp_session_destroy(s); - scp_connection_destroy(c); - /*free_stream(c.in_s); - free_stream(c.out_s);*/ + g_printf("001 - send connect request\n"); - return 0; + scp_session_set_type(s, SCP_SESSION_TYPE_XVNC); + scp_session_set_version(s, 1); + scp_session_set_height(s, 600); + scp_session_set_width(s, 800); + scp_session_set_bpp(s, 16); + scp_session_set_rsr(s, 0); + scp_session_set_locale(s, "it_IT"); + scp_session_set_username(s, "prog"); + scp_session_set_password(s, "prog"); + scp_session_set_hostname(s, "odin"); + // scp_session_set_addr(s, SCP_ADDRESS_TYPE_IPV4, "127.0.0.1"); + // scp_session_set_display(struct SCP_SESSION* s, SCP_DISPLAY display); + // scp_session_set_errstr(struct SCP_SESSION* s, char* str); + + /*s.type=SCP_SESSION_TYPE_XVNC; + s.version=1; + s.height=600; + s.width=800; + s.bpp=8; + s.rsr=0; + g_strncpy(s.locale,"it_IT 0123456789",18); + s.username=g_malloc(256, 1); + g_strncpy(s.username,"prog",255); + s.password=g_malloc(256,1); + g_strncpy(s.password, "prog", 255); + g_printf("%s - %s\n", s.username, s.password); + s.hostname=g_malloc(256,1); + g_strncpy(s.hostname, "odin", 255); + s.addr_type=SCP_ADDRESS_TYPE_IPV4; + s.ipv4addr=0; + s.errstr=0;*/ + + end = 0; + e = scp_v1c_connect(c, s); + + while (!end) + { + switch (e) + { + case SCP_CLIENT_STATE_OK: + g_printf("OK : display is %d\n", (short int)s->display); + end = 1; + break; + case SCP_CLIENT_STATE_SESSION_LIST: + g_printf("OK : session list needed\n"); + e = scp_v1c_get_session_list(c, &scnt, &dsl); + break; + case SCP_CLIENT_STATE_LIST_OK: + g_printf("OK : selecting a session:\n"); + + for (idx = 0; idx < scnt; idx++) + { + printf("Session \t%d - %d - %dx%dx%d - %d %d %d - %4d/%2d/%2d@%2d:%2d\n", \ + (dsl[idx]).SID, (dsl[idx]).type, (dsl[idx]).width, (dsl[idx]).height, (dsl[idx]).bpp, \ + (dsl[idx]).idle_days, (dsl[idx]).idle_hours, (dsl[idx]).idle_minutes, \ + (dsl[idx]).conn_year, (dsl[idx]).conn_month, (dsl[idx]).conn_day, (dsl[idx]).conn_hour, (dsl[idx]).conn_minute); + } + + sel = menuSelect(scnt); + e = scp_v1c_select_session(c, s, dsl[sel - 1].SID); + g_printf("\n return: %d \n", e); + break; + case SCP_CLIENT_STATE_RESEND_CREDENTIALS: + g_printf("ERR: resend credentials - %s\n", s->errstr); + g_printf(" username:"); + + if (scanf("%255s", buf) < 0) + { + g_writeln("error"); + } + + scp_session_set_username(s, buf); + g_printf(" password:"); + + if (scanf("%255s", buf) < 0) + { + g_writeln("error"); + } + + scp_session_set_password(s, buf); + e = scp_v1c_resend_credentials(c, s); + break; + case SCP_CLIENT_STATE_CONNECTION_DENIED: + g_printf("ERR: connection denied: %s\n", s->errstr); + end = 1; + break; + case SCP_CLIENT_STATE_PWD_CHANGE_REQ: + g_printf("OK : password change required\n"); + break; + /*case SCP_CLIENT_STATE_RECONNECT_SINGLE: + g_printf("OK : reconnect to 1 disconnected session\n"); + e=scp_v1c_retrieve_session(&c, &s, &ds); + g_printf("Session Type: %d on %d\n", ds.type, s.display); + g_printf("Session Screen: %dx%dx%d\n", ds.height, ds.width, ds.bpp);*/ + break; + default: + g_printf("protocol error: %d\n", e); + end = 1; + } + } + + g_tcp_close(sock); + scp_session_destroy(s); + scp_connection_destroy(c); + /*free_stream(c.in_s); + free_stream(c.out_s);*/ + + return 0; } -int inputSession(struct SCP_SESSION* s) +int inputSession(struct SCP_SESSION *s) { - unsigned int integer; + unsigned int integer; - g_printf("username: "); - if (scanf("%255s", s->username) < 0) - { - g_writeln("error"); - } - g_printf("password:"); - if (scanf("%255s", s->password) < 0) - { - g_writeln("error"); - } - g_printf("hostname:"); - if (scanf("%255s", s->hostname) < 0) - { - g_writeln("error"); - } + g_printf("username: "); - g_printf("session type:\n"); - g_printf("0: Xvnc\n", SCP_SESSION_TYPE_XVNC); - g_printf("1: x11rdp\n", SCP_SESSION_TYPE_XRDP); - integer=menuSelect(1); - if (integer==1) - { - s->type=SCP_SESSION_TYPE_XRDP; - } - else - { - s->type=SCP_SESSION_TYPE_XVNC; - } + if (scanf("%255s", s->username) < 0) + { + g_writeln("error"); + } - s->version=1; - s->height=600; - s->width=800; - s->bpp=8; + g_printf("password:"); - /* fixed for now */ - s->rsr=0; - g_strncpy(s->locale,"it_IT 0123456789",18); + if (scanf("%255s", s->password) < 0) + { + g_writeln("error"); + } - return 0; + g_printf("hostname:"); + + if (scanf("%255s", s->hostname) < 0) + { + g_writeln("error"); + } + + g_printf("session type:\n"); + g_printf("0: Xvnc\n", SCP_SESSION_TYPE_XVNC); + g_printf("1: x11rdp\n", SCP_SESSION_TYPE_XRDP); + integer = menuSelect(1); + + if (integer == 1) + { + s->type = SCP_SESSION_TYPE_XRDP; + } + else + { + s->type = SCP_SESSION_TYPE_XVNC; + } + + s->version = 1; + s->height = 600; + s->width = 800; + s->bpp = 8; + + /* fixed for now */ + s->rsr = 0; + g_strncpy(s->locale, "it_IT 0123456789", 18); + + return 0; } tui32 menuSelect(tui32 choices) { - tui32 sel; - int ret; + tui32 sel; + int ret; - ret = scanf("%u", &sel); - - while ((ret == 0) || (sel > choices)) - { - g_printf("invalid choice."); ret = scanf("%u", &sel); - } - return sel; + while ((ret == 0) || (sel > choices)) + { + g_printf("invalid choice."); + ret = scanf("%u", &sel); + } + + return sel; } diff --git a/sesman/tools/tcp.c b/sesman/tools/tcp.c index 1cba18d6..c8d01e96 100644 --- a/sesman/tools/tcp.c +++ b/sesman/tools/tcp.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -35,111 +34,113 @@ /*****************************************************************************/ int DEFAULT_CC -tcp_force_recv(int sck, char* data, int len) +tcp_force_recv(int sck, char *data, int len) { - int rcvd; + int rcvd; -//#ifndef LIBSCP_CLIENT -// int block; -// block = lock_fork_critical_section_start(); -//#endif + //#ifndef LIBSCP_CLIENT + // int block; + // block = lock_fork_critical_section_start(); + //#endif - while (len > 0) - { - rcvd = g_tcp_recv(sck, data, len, 0); - if (rcvd == -1) + while (len > 0) { - if (g_tcp_last_error_would_block(sck)) - { - g_sleep(1); - } - else - { -//#ifndef LIBSCP_CLIENT -// lock_fork_critical_section_end(block); -//#endif - return 1; - } - } - else if (rcvd == 0) - { -//#ifndef LIBSCP_CLIENT -// lock_fork_critical_section_end(block); -//#endif - return 1; - } - else - { - data += rcvd; - len -= rcvd; - } - } + rcvd = g_tcp_recv(sck, data, len, 0); -//#ifndef LIBSCP_CLIENT -// lock_fork_critical_section_end(block); -//#endif + if (rcvd == -1) + { + if (g_tcp_last_error_would_block(sck)) + { + g_sleep(1); + } + else + { + //#ifndef LIBSCP_CLIENT + // lock_fork_critical_section_end(block); + //#endif + return 1; + } + } + else if (rcvd == 0) + { + //#ifndef LIBSCP_CLIENT + // lock_fork_critical_section_end(block); + //#endif + return 1; + } + else + { + data += rcvd; + len -= rcvd; + } + } - return 0; + //#ifndef LIBSCP_CLIENT + // lock_fork_critical_section_end(block); + //#endif + + return 0; } /*****************************************************************************/ int DEFAULT_CC -tcp_force_send(int sck, char* data, int len) +tcp_force_send(int sck, char *data, int len) { - int sent; + int sent; -//#ifndef LIBSCP_CLIENT -// int block; -// block = lock_fork_critical_section_start(); -//#endif + //#ifndef LIBSCP_CLIENT + // int block; + // block = lock_fork_critical_section_start(); + //#endif - while (len > 0) - { - sent = g_tcp_send(sck, data, len, 0); - if (sent == -1) + while (len > 0) { - if (g_tcp_last_error_would_block(sck)) - { - g_sleep(1); - } - else - { -//#ifndef LIBSCP_CLIENT -// lock_fork_critical_section_end(block); -//#endif - return 1; - } - } - else if (sent == 0) - { -//#ifndef LIBSCP_CLIENT -// lock_fork_critical_section_end(block); -//#endif - return 1; - } - else - { - data += sent; - len -= sent; - } - } + sent = g_tcp_send(sck, data, len, 0); -//#ifndef LIBSCP_CLIENT -// lock_fork_critical_section_end(block); -//#endif + if (sent == -1) + { + if (g_tcp_last_error_would_block(sck)) + { + g_sleep(1); + } + else + { + //#ifndef LIBSCP_CLIENT + // lock_fork_critical_section_end(block); + //#endif + return 1; + } + } + else if (sent == 0) + { + //#ifndef LIBSCP_CLIENT + // lock_fork_critical_section_end(block); + //#endif + return 1; + } + else + { + data += sent; + len -= sent; + } + } - return 0; + //#ifndef LIBSCP_CLIENT + // lock_fork_critical_section_end(block); + //#endif + + return 0; } /*****************************************************************************/ int DEFAULT_CC -tcp_bind(int sck, char* addr, char* port) +tcp_bind(int sck, char *addr, char *port) { - struct sockaddr_in s; + struct sockaddr_in s; - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons(atoi(port)); - s.sin_addr.s_addr = inet_addr(addr); - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons(atoi(port)); + s.sin_addr.s_addr = inet_addr(addr); + return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); } diff --git a/sesman/tools/tcp.h b/sesman/tools/tcp.h index 5de12f18..2fd7963e 100644 --- a/sesman/tools/tcp.h +++ b/sesman/tools/tcp.h @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2010 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * diff --git a/sesman/tools/xcon.c b/sesman/tools/xcon.c index 7a45a1cd..bb715054 100644 --- a/sesman/tools/xcon.c +++ b/sesman/tools/xcon.c @@ -1,35 +1,58 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #include #include #include -Display* g_display = 0; +Display *g_display = 0; int g_x_socket = 0; -int main(int argc, char** argv) +int main(int argc, char **argv) { - fd_set rfds; - int i1; - XEvent xevent; + fd_set rfds; + int i1; + XEvent xevent; - g_display = XOpenDisplay(0); - if (g_display == 0) - { - printf("XOpenDisplay failed\n"); - return 0; - } - g_x_socket = XConnectionNumber(g_display); - while (1) - { - FD_ZERO(&rfds); - FD_SET(g_x_socket, &rfds); - i1 = select(g_x_socket + 1, &rfds, 0, 0, 0); - if (i1 < 0) + g_display = XOpenDisplay(0); + + if (g_display == 0) { - break; + printf("XOpenDisplay failed\n"); + return 0; } - XNextEvent(g_display, &xevent); - } - return 0; + + g_x_socket = XConnectionNumber(g_display); + + while (1) + { + FD_ZERO(&rfds); + FD_SET(g_x_socket, &rfds); + i1 = select(g_x_socket + 1, &rfds, 0, 0, 0); + + if (i1 < 0) + { + break; + } + + XNextEvent(g_display, &xevent); + } + + return 0; } diff --git a/sesman/verify_user.c b/sesman/verify_user.c index aaa1515c..8765d7c2 100644 --- a/sesman/verify_user.c +++ b/sesman/verify_user.c @@ -1,21 +1,20 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * @@ -38,77 +37,89 @@ #define SECS_PER_DAY (24L*3600L) #endif -extern struct config_sesman* g_cfg; /* in sesman.c */ +extern struct config_sesman *g_cfg; /* in sesman.c */ static int DEFAULT_CC -auth_crypt_pwd(char* pwd, char* pln, char* crp); +auth_crypt_pwd(char *pwd, char *pln, char *crp); static int DEFAULT_CC -auth_account_disabled(struct spwd* stp); +auth_account_disabled(struct spwd *stp); /******************************************************************************/ /* returns boolean */ long DEFAULT_CC -auth_userpass(char* user, char* pass) +auth_userpass(char *user, char *pass) { - char salt[13] = "$1$"; - char hash[35] = ""; - char* encr = 0; - struct passwd* spw; - struct spwd* stp; - int saltcnt = 0; + char salt[13] = "$1$"; + char hash[35] = ""; + char *encr = 0; + struct passwd *spw; + struct spwd *stp; + int saltcnt = 0; - spw = getpwnam(user); - if (spw == 0) - { - return 0; - } - if (g_strncmp(spw->pw_passwd, "x", 3) == 0) - { - /* the system is using shadow */ - stp = getspnam(user); - if (stp == 0) + spw = getpwnam(user); + + if (spw == 0) { - return 0; + return 0; } - if (1==auth_account_disabled(stp)) + + if (g_strncmp(spw->pw_passwd, "x", 3) == 0) { - log_message(&(g_cfg->log), LOG_LEVEL_INFO, "account %s is disabled", user); - return 0; + /* the system is using shadow */ + stp = getspnam(user); + + if (stp == 0) + { + return 0; + } + + if (1 == auth_account_disabled(stp)) + { + log_message(&(g_cfg->log), LOG_LEVEL_INFO, "account %s is disabled", user); + return 0; + } + + g_strncpy(hash, stp->sp_pwdp, 34); } - g_strncpy(hash, stp->sp_pwdp, 34); - } - else - { - /* old system with only passwd */ - g_strncpy(hash, spw->pw_passwd, 34); - } - hash[34] = '\0'; - if (g_strncmp(hash, "$1$", 3) == 0) - { - /* gnu style crypt(); */ - saltcnt = 3; - while ((hash[saltcnt] != '$') && (saltcnt < 11)) + else { - salt[saltcnt] = hash[saltcnt]; - saltcnt++; + /* old system with only passwd */ + g_strncpy(hash, spw->pw_passwd, 34); } - salt[saltcnt] = '$'; - salt[saltcnt + 1] = '\0'; - } - else - { - /* classic two char salt */ - salt[0] = hash[0]; - salt[1] = hash[1]; - salt[2] = '\0'; - } - encr = crypt(pass,salt); - if (g_strncmp(encr, hash, 34) != 0) - { - return 0; - } - return 1; + + hash[34] = '\0'; + + if (g_strncmp(hash, "$1$", 3) == 0) + { + /* gnu style crypt(); */ + saltcnt = 3; + + while ((hash[saltcnt] != '$') && (saltcnt < 11)) + { + salt[saltcnt] = hash[saltcnt]; + saltcnt++; + } + + salt[saltcnt] = '$'; + salt[saltcnt + 1] = '\0'; + } + else + { + /* classic two char salt */ + salt[0] = hash[0]; + salt[1] = hash[1]; + salt[2] = '\0'; + } + + encr = crypt(pass, salt); + + if (g_strncmp(encr, hash, 34) != 0) + { + return 0; + } + + return 1; } /******************************************************************************/ @@ -116,138 +127,144 @@ auth_userpass(char* user, char* pass) int DEFAULT_CC auth_start_session(long in_val, int in_display) { - return 0; + return 0; } /******************************************************************************/ int DEFAULT_CC auth_end(long in_val) { - return 0; + return 0; } /******************************************************************************/ int DEFAULT_CC auth_set_env(long in_val) { - return 0; + return 0; } /******************************************************************************/ int DEFAULT_CC -auth_check_pwd_chg(char* user) +auth_check_pwd_chg(char *user) { - struct passwd* spw; - struct spwd* stp; - int now; - long today; + struct passwd *spw; + struct spwd *stp; + int now; + long today; + + spw = getpwnam(user); + + if (spw == 0) + { + return AUTH_PWD_CHG_ERROR; + } + + if (g_strncmp(spw->pw_passwd, "x", 3) != 0) + { + /* old system with only passwd */ + return AUTH_PWD_CHG_OK; + } + + /* the system is using shadow */ + stp = getspnam(user); + + if (stp == 0) + { + return AUTH_PWD_CHG_ERROR; + } + + /* check if we need a pwd change */ + now = g_time1(); + today = now / SECS_PER_DAY; + + if (stp->sp_expire == -1) + { + return AUTH_PWD_CHG_OK; + } + + if (today >= (stp->sp_lstchg + stp->sp_max - stp->sp_warn)) + { + return AUTH_PWD_CHG_CHANGE; + } + + if (today >= (stp->sp_lstchg + stp->sp_max)) + { + return AUTH_PWD_CHG_CHANGE_MANDATORY; + } + + if (today < ((stp->sp_lstchg) + (stp->sp_min))) + { + /* cannot change pwd for now */ + return AUTH_PWD_CHG_NOT_NOW; + } - spw = getpwnam(user); - if (spw == 0) - { - return AUTH_PWD_CHG_ERROR; - } - if (g_strncmp(spw->pw_passwd, "x", 3) != 0) - { - /* old system with only passwd */ return AUTH_PWD_CHG_OK; - } - - /* the system is using shadow */ - stp = getspnam(user); - if (stp == 0) - { - return AUTH_PWD_CHG_ERROR; - } - - /* check if we need a pwd change */ - now=g_time1(); - today=now/SECS_PER_DAY; - - if (stp->sp_expire == -1) - { - return AUTH_PWD_CHG_OK; - } - if (today >= (stp->sp_lstchg + stp->sp_max - stp->sp_warn)) - { - return AUTH_PWD_CHG_CHANGE; - } - - if (today >= (stp->sp_lstchg + stp->sp_max)) - { - return AUTH_PWD_CHG_CHANGE_MANDATORY; - } - - if (today < ((stp->sp_lstchg)+(stp->sp_min))) - { - /* cannot change pwd for now */ - return AUTH_PWD_CHG_NOT_NOW; - } - - return AUTH_PWD_CHG_OK; } int DEFAULT_CC -auth_change_pwd(char* user, char* newpwd) +auth_change_pwd(char *user, char *newpwd) { - struct passwd* spw; - struct spwd* stp; - char hash[35] = ""; - long today; + struct passwd *spw; + struct spwd *stp; + char hash[35] = ""; + long today; - FILE* fd; + FILE *fd; - if (0 != lckpwdf()) - { - return 1; - } - - /* open passwd */ - spw = getpwnam(user); - if (spw == 0) - { - return 1; - } - - if (g_strncmp(spw->pw_passwd, "x", 3) != 0) - { - /* old system with only passwd */ - if (auth_crypt_pwd(spw->pw_passwd, newpwd, hash) != 0) + if (0 != lckpwdf()) { - ulckpwdf(); - return 1; + return 1; } - spw->pw_passwd=g_strdup(hash); - fd = fopen("/etc/passwd", "rw"); - putpwent(spw, fd); - } - else - { - /* the system is using shadow */ - stp = getspnam(user); - if (stp == 0) + /* open passwd */ + spw = getpwnam(user); + + if (spw == 0) { - return 1; + return 1; } - /* old system with only passwd */ - if (auth_crypt_pwd(stp->sp_pwdp, newpwd, hash) != 0) + if (g_strncmp(spw->pw_passwd, "x", 3) != 0) { - ulckpwdf(); - return 1; + /* old system with only passwd */ + if (auth_crypt_pwd(spw->pw_passwd, newpwd, hash) != 0) + { + ulckpwdf(); + return 1; + } + + spw->pw_passwd = g_strdup(hash); + fd = fopen("/etc/passwd", "rw"); + putpwent(spw, fd); + } + else + { + /* the system is using shadow */ + stp = getspnam(user); + + if (stp == 0) + { + return 1; + } + + /* old system with only passwd */ + if (auth_crypt_pwd(stp->sp_pwdp, newpwd, hash) != 0) + { + ulckpwdf(); + return 1; + } + + stp->sp_pwdp = g_strdup(hash); + today = g_time1() / SECS_PER_DAY; + stp->sp_lstchg = today; + stp->sp_expire = today + stp->sp_max + stp->sp_inact; + fd = fopen("/etc/shadow", "rw"); + putspent(stp, fd); } - stp->sp_pwdp = g_strdup(hash); - today = g_time1() / SECS_PER_DAY; - stp->sp_lstchg = today; - stp->sp_expire = today + stp->sp_max + stp->sp_inact; - fd = fopen("/etc/shadow", "rw"); - putspent(stp, fd); - } - - ulckpwdf(); - return 0; + ulckpwdf(); + return 0; } /** @@ -260,36 +277,38 @@ auth_change_pwd(char* user, char* newpwd) */ static int DEFAULT_CC -auth_crypt_pwd(char* pwd, char* pln, char* crp) +auth_crypt_pwd(char *pwd, char *pln, char *crp) { - char salt[13] = "$1$"; - int saltcnt = 0; - char* encr; + char salt[13] = "$1$"; + int saltcnt = 0; + char *encr; - if (g_strncmp(pwd, "$1$", 3) == 0) - { - /* gnu style crypt(); */ - saltcnt = 3; - while ((pwd[saltcnt] != '$') && (saltcnt < 11)) + if (g_strncmp(pwd, "$1$", 3) == 0) { - salt[saltcnt] = pwd[saltcnt]; - saltcnt++; + /* gnu style crypt(); */ + saltcnt = 3; + + while ((pwd[saltcnt] != '$') && (saltcnt < 11)) + { + salt[saltcnt] = pwd[saltcnt]; + saltcnt++; + } + + salt[saltcnt] = '$'; + salt[saltcnt + 1] = '\0'; + } + else + { + /* classic two char salt */ + salt[0] = pwd[0]; + salt[1] = pwd[1]; + salt[2] = '\0'; } - salt[saltcnt] = '$'; - salt[saltcnt + 1] = '\0'; - } - else - { - /* classic two char salt */ - salt[0] = pwd[0]; - salt[1] = pwd[1]; - salt[2] = '\0'; - } - encr = crypt(pln, salt); - g_strncpy(crp, encr, 34); + encr = crypt(pln, salt); + g_strncpy(crp, encr, 34); - return 0; + return 0; } /** @@ -298,35 +317,35 @@ auth_crypt_pwd(char* pwd, char* pln, char* crp) * */ static int DEFAULT_CC -auth_account_disabled(struct spwd* stp) +auth_account_disabled(struct spwd *stp) { - int today; + int today; - if (0 == stp) - { - /* if an invalid struct was passed we assume a disabled account */ - return 1; - } + if (0 == stp) + { + /* if an invalid struct was passed we assume a disabled account */ + return 1; + } - today = g_time1() / SECS_PER_DAY; + today = g_time1() / SECS_PER_DAY; - LOG_DBG("last %d",stp->sp_lstchg); - LOG_DBG("min %d",stp->sp_min); - LOG_DBG("max %d",stp->sp_max); - LOG_DBG("inact %d",stp->sp_inact); - LOG_DBG("warn %d",stp->sp_warn); - LOG_DBG("expire %d",stp->sp_expire); - LOG_DBG("today %d",today); + LOG_DBG("last %d", stp->sp_lstchg); + LOG_DBG("min %d", stp->sp_min); + LOG_DBG("max %d", stp->sp_max); + LOG_DBG("inact %d", stp->sp_inact); + LOG_DBG("warn %d", stp->sp_warn); + LOG_DBG("expire %d", stp->sp_expire); + LOG_DBG("today %d", today); - if ((stp->sp_expire != -1) && (today >= stp->sp_expire)) - { - return 1; - } + if ((stp->sp_expire != -1) && (today >= stp->sp_expire)) + { + return 1; + } - if (today >= (stp->sp_lstchg+stp->sp_max+stp->sp_inact)) - { - return 1; - } + if (today >= (stp->sp_lstchg + stp->sp_max + stp->sp_inact)) + { + return 1; + } - return 0; + return 0; } diff --git a/sesman/verify_user_kerberos.c b/sesman/verify_user_kerberos.c index 68b232af..c4a7ecde 100644 --- a/sesman/verify_user_kerberos.c +++ b/sesman/verify_user_kerberos.c @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file verify_user_kerberos.c * @brief Authenticate user using kerberos * @author Jay Sorg - * + * */ #include "arch.h" @@ -34,346 +33,393 @@ typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type; struct k_opts { - /* in seconds */ - krb5_deltat starttime; - krb5_deltat lifetime; - krb5_deltat rlife; + /* in seconds */ + krb5_deltat starttime; + krb5_deltat lifetime; + krb5_deltat rlife; - int forwardable; - int proxiable; - int addresses; + int forwardable; + int proxiable; + int addresses; - int not_forwardable; - int not_proxiable; - int no_addresses; + int not_forwardable; + int not_proxiable; + int no_addresses; - int verbose; + int verbose; - char* principal_name; - char* service_name; - char* keytab_name; - char* k5_cache_name; - char* k4_cache_name; + char *principal_name; + char *service_name; + char *keytab_name; + char *k5_cache_name; + char *k4_cache_name; - action_type action; + action_type action; }; struct k5_data { - krb5_context ctx; - krb5_ccache cc; - krb5_principal me; - char* name; + krb5_context ctx; + krb5_ccache cc; + krb5_principal me; + char *name; }; struct user_info { - char* name; - char* pass; + char *name; + char *pass; }; /******************************************************************************/ /* returns boolean */ static int DEFAULT_CC -k5_begin(struct k_opts* opts, struct k5_data* k5, struct user_info* u_info) +k5_begin(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) { - krb5_error_code code = 0; + krb5_error_code code = 0; + + code = krb5_init_context(&k5->ctx); - code = krb5_init_context(&k5->ctx); - if (code != 0) - { - g_printf("krb5_init_context failed in k5_begin\n"); - return 0; - } - if (opts->k5_cache_name) - { - code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc); if (code != 0) { - g_printf("krb5_cc_resolve failed in k5_begin\n"); - return 0; - } - } - else - { - code = krb5_cc_default(k5->ctx, &k5->cc); - if (code != 0) - { - g_printf("krb5_cc_default failed in k5_begin\n"); - return 0; - } - } - if (opts->principal_name) - { - /* Use specified name */ - code = krb5_parse_name(k5->ctx, opts->principal_name, &k5->me); - if (code != 0) - { - g_printf("krb5_parse_name failed in k5_begin\n"); - return 0; - } - } - else - { - /* No principal name specified */ - if (opts->action == INIT_KT) - { - /* Use the default host/service name */ - code = krb5_sname_to_principal(k5->ctx, NULL, NULL, - KRB5_NT_SRV_HST, &k5->me); - if (code != 0) - { - g_printf("krb5_sname_to_principal failed in k5_begin\n"); + g_printf("krb5_init_context failed in k5_begin\n"); return 0; - } + } + + if (opts->k5_cache_name) + { + code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc); + + if (code != 0) + { + g_printf("krb5_cc_resolve failed in k5_begin\n"); + return 0; + } } else { - /* Get default principal from cache if one exists */ - code = krb5_cc_get_principal(k5->ctx, k5->cc, &k5->me); - if (code != 0) - { - code = krb5_parse_name(k5->ctx, u_info->name, &k5->me); + code = krb5_cc_default(k5->ctx, &k5->cc); + if (code != 0) { - g_printf("krb5_parse_name failed in k5_begin\n"); - return 0; + g_printf("krb5_cc_default failed in k5_begin\n"); + return 0; } - } } - } - code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); - if (code != 0) - { - g_printf("krb5_unparse_name failed in k5_begin\n"); - return 0; - } - opts->principal_name = k5->name; - return 1; + + if (opts->principal_name) + { + /* Use specified name */ + code = krb5_parse_name(k5->ctx, opts->principal_name, &k5->me); + + if (code != 0) + { + g_printf("krb5_parse_name failed in k5_begin\n"); + return 0; + } + } + else + { + /* No principal name specified */ + if (opts->action == INIT_KT) + { + /* Use the default host/service name */ + code = krb5_sname_to_principal(k5->ctx, NULL, NULL, + KRB5_NT_SRV_HST, &k5->me); + + if (code != 0) + { + g_printf("krb5_sname_to_principal failed in k5_begin\n"); + return 0; + } + } + else + { + /* Get default principal from cache if one exists */ + code = krb5_cc_get_principal(k5->ctx, k5->cc, &k5->me); + + if (code != 0) + { + code = krb5_parse_name(k5->ctx, u_info->name, &k5->me); + + if (code != 0) + { + g_printf("krb5_parse_name failed in k5_begin\n"); + return 0; + } + } + } + } + + code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); + + if (code != 0) + { + g_printf("krb5_unparse_name failed in k5_begin\n"); + return 0; + } + + opts->principal_name = k5->name; + return 1; } /******************************************************************************/ static void DEFAULT_CC -k5_end(struct k5_data* k5) +k5_end(struct k5_data *k5) { - if (k5->name) - { - krb5_free_unparsed_name(k5->ctx, k5->name); - } - if (k5->me) - { - krb5_free_principal(k5->ctx, k5->me); - } - if (k5->cc) - { - krb5_cc_close(k5->ctx, k5->cc); - } - if (k5->ctx) - { - krb5_free_context(k5->ctx); - } - g_memset(k5, 0, sizeof(struct k5_data)); + if (k5->name) + { + krb5_free_unparsed_name(k5->ctx, k5->name); + } + + if (k5->me) + { + krb5_free_principal(k5->ctx, k5->me); + } + + if (k5->cc) + { + krb5_cc_close(k5->ctx, k5->cc); + } + + if (k5->ctx) + { + krb5_free_context(k5->ctx); + } + + g_memset(k5, 0, sizeof(struct k5_data)); } /******************************************************************************/ static krb5_error_code KRB5_CALLCONV -kinit_prompter(krb5_context ctx, void* data, const char* name, - const char* banner, int num_prompts, krb5_prompt prompts[]) +kinit_prompter(krb5_context ctx, void *data, const char *name, + const char *banner, int num_prompts, krb5_prompt prompts[]) { - int i; - krb5_prompt_type* types; - krb5_error_code rc; - struct user_info* u_info; + int i; + krb5_prompt_type *types; + krb5_error_code rc; + struct user_info *u_info; - u_info = (struct user_info*)data; - rc = 0; - types = krb5_get_prompt_types(ctx); - for (i = 0; i < num_prompts; i++) - { - if (types[i] == KRB5_PROMPT_TYPE_PASSWORD || - types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) + u_info = (struct user_info *)data; + rc = 0; + types = krb5_get_prompt_types(ctx); + + for (i = 0; i < num_prompts; i++) { - g_strncpy(prompts[i].reply->data, u_info->pass, 255); + if (types[i] == KRB5_PROMPT_TYPE_PASSWORD || + types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) + { + g_strncpy(prompts[i].reply->data, u_info->pass, 255); + } } - } - return rc; + + return rc; } /******************************************************************************/ /* returns boolean */ static int -k5_kinit(struct k_opts* opts, struct k5_data* k5, struct user_info* u_info) +k5_kinit(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) { - char* doing; - int notix = 1; - krb5_keytab keytab = 0; - krb5_creds my_creds; - krb5_error_code code = 0; - krb5_get_init_creds_opt options; - krb5_address** addresses; + char *doing; + int notix = 1; + krb5_keytab keytab = 0; + krb5_creds my_creds; + krb5_error_code code = 0; + krb5_get_init_creds_opt options; + krb5_address **addresses; - krb5_get_init_creds_opt_init(&options); - g_memset(&my_creds, 0, sizeof(my_creds)); - /* - From this point on, we can goto cleanup because my_creds is - initialized. - */ - if (opts->lifetime) - { - krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime); - } - if (opts->rlife) - { - krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife); - } - if (opts->forwardable) - { - krb5_get_init_creds_opt_set_forwardable(&options, 1); - } - if (opts->not_forwardable) - { - krb5_get_init_creds_opt_set_forwardable(&options, 0); - } - if (opts->proxiable) - { - krb5_get_init_creds_opt_set_proxiable(&options, 1); - } - if (opts->not_proxiable) - { - krb5_get_init_creds_opt_set_proxiable(&options, 0); - } - if (opts->addresses) - { - addresses = NULL; - code = krb5_os_localaddr(k5->ctx, &addresses); - if (code != 0) + krb5_get_init_creds_opt_init(&options); + g_memset(&my_creds, 0, sizeof(my_creds)); + + /* + From this point on, we can goto cleanup because my_creds is + initialized. + */ + if (opts->lifetime) { - g_printf("krb5_os_localaddr failed in k5_kinit\n"); - goto cleanup; + krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime); } - krb5_get_init_creds_opt_set_address_list(&options, addresses); - } - if (opts->no_addresses) - { - krb5_get_init_creds_opt_set_address_list(&options, NULL); - } - if ((opts->action == INIT_KT) && opts->keytab_name) - { - code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); - if (code != 0) + + if (opts->rlife) { - g_printf("krb5_kt_resolve failed in k5_kinit\n"); - goto cleanup; + krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife); } - } - switch (opts->action) - { - case INIT_PW: - code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, - 0, kinit_prompter, u_info, - opts->starttime, - opts->service_name, - &options); - break; - case INIT_KT: - code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, - keytab, - opts->starttime, - opts->service_name, - &options); - break; - case VALIDATE: - code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc, - opts->service_name); - break; - case RENEW: - code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc, - opts->service_name); - break; - } - if (code != 0) - { - doing = 0; + + if (opts->forwardable) + { + krb5_get_init_creds_opt_set_forwardable(&options, 1); + } + + if (opts->not_forwardable) + { + krb5_get_init_creds_opt_set_forwardable(&options, 0); + } + + if (opts->proxiable) + { + krb5_get_init_creds_opt_set_proxiable(&options, 1); + } + + if (opts->not_proxiable) + { + krb5_get_init_creds_opt_set_proxiable(&options, 0); + } + + if (opts->addresses) + { + addresses = NULL; + code = krb5_os_localaddr(k5->ctx, &addresses); + + if (code != 0) + { + g_printf("krb5_os_localaddr failed in k5_kinit\n"); + goto cleanup; + } + + krb5_get_init_creds_opt_set_address_list(&options, addresses); + } + + if (opts->no_addresses) + { + krb5_get_init_creds_opt_set_address_list(&options, NULL); + } + + if ((opts->action == INIT_KT) && opts->keytab_name) + { + code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); + + if (code != 0) + { + g_printf("krb5_kt_resolve failed in k5_kinit\n"); + goto cleanup; + } + } + switch (opts->action) { - case INIT_PW: - case INIT_KT: - doing = "getting initial credentials"; - break; - case VALIDATE: - doing = "validating credentials"; - break; - case RENEW: - doing = "renewing credentials"; - break; + case INIT_PW: + code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, + 0, kinit_prompter, u_info, + opts->starttime, + opts->service_name, + &options); + break; + case INIT_KT: + code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, + keytab, + opts->starttime, + opts->service_name, + &options); + break; + case VALIDATE: + code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc, + opts->service_name); + break; + case RENEW: + code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc, + opts->service_name); + break; } - if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) + + if (code != 0) { - g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing); + doing = 0; + + switch (opts->action) + { + case INIT_PW: + case INIT_KT: + doing = "getting initial credentials"; + break; + case VALIDATE: + doing = "validating credentials"; + break; + case RENEW: + doing = "renewing credentials"; + break; + } + + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) + { + g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing); + } + else + { + g_printf("sesman: error while %s in k5_kinit\n", doing); + } + + goto cleanup; } - else + + if (!opts->lifetime) { - g_printf("sesman: error while %s in k5_kinit\n", doing); + /* We need to figure out what lifetime to use for Kerberos 4. */ + opts->lifetime = my_creds.times.endtime - my_creds.times.authtime; } - goto cleanup; - } - if (!opts->lifetime) - { - /* We need to figure out what lifetime to use for Kerberos 4. */ - opts->lifetime = my_creds.times.endtime - my_creds.times.authtime; - } - code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me); - if (code != 0) - { - g_printf("krb5_cc_initialize failed in k5_kinit\n"); - goto cleanup; - } - code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds); - if (code != 0) - { - g_printf("krb5_cc_store_cred failed in k5_kinit\n"); - goto cleanup; - } - notix = 0; + + code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me); + + if (code != 0) + { + g_printf("krb5_cc_initialize failed in k5_kinit\n"); + goto cleanup; + } + + code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds); + + if (code != 0) + { + g_printf("krb5_cc_store_cred failed in k5_kinit\n"); + goto cleanup; + } + + notix = 0; cleanup: - if (my_creds.client == k5->me) - { - my_creds.client = 0; - } - krb5_free_cred_contents(k5->ctx, &my_creds); - if (keytab) - { - krb5_kt_close(k5->ctx, keytab); - } - return notix ? 0 : 1; + + if (my_creds.client == k5->me) + { + my_creds.client = 0; + } + + krb5_free_cred_contents(k5->ctx, &my_creds); + + if (keytab) + { + krb5_kt_close(k5->ctx, keytab); + } + + return notix ? 0 : 1; } /******************************************************************************/ /* returns boolean */ int DEFAULT_CC -auth_userpass(char* user, char* pass) +auth_userpass(char *user, char *pass) { - struct k_opts opts; - struct k5_data k5; - struct user_info u_info; - int got_k5; - int authed_k5; + struct k_opts opts; + struct k5_data k5; + struct user_info u_info; + int got_k5; + int authed_k5; - g_memset(&opts, 0, sizeof(opts)); - opts.action = INIT_PW; - g_memset(&k5, 0, sizeof(k5)); - g_memset(&u_info, 0, sizeof(u_info)); - u_info.name = user; - u_info.pass = pass; - authed_k5 = 0; - got_k5 = k5_begin(&opts, &k5, &u_info); - if (got_k5) - { - authed_k5 = k5_kinit(&opts, &k5, &u_info); - k5_end(&k5); - } - return authed_k5; + g_memset(&opts, 0, sizeof(opts)); + opts.action = INIT_PW; + g_memset(&k5, 0, sizeof(k5)); + g_memset(&u_info, 0, sizeof(u_info)); + u_info.name = user; + u_info.pass = pass; + authed_k5 = 0; + got_k5 = k5_begin(&opts, &k5, &u_info); + + if (got_k5) + { + authed_k5 = k5_kinit(&opts, &k5, &u_info); + k5_end(&k5); + } + + return authed_k5; } /******************************************************************************/ @@ -381,19 +427,19 @@ auth_userpass(char* user, char* pass) int DEFAULT_CC auth_start_session(void) { - return 0; + return 0; } /******************************************************************************/ int DEFAULT_CC auth_end(void) { - return 0; + return 0; } /******************************************************************************/ int DEFAULT_CC auth_set_env(void) { - return 0; + return 0; } diff --git a/sesman/verify_user_pam.c b/sesman/verify_user_pam.c index e3d8596e..b81398de 100644 --- a/sesman/verify_user_pam.c +++ b/sesman/verify_user_pam.c @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file verify_user_pam.c * @brief Authenticate user using pam * @author Jay Sorg - * + * */ #include "arch.h" @@ -33,107 +32,116 @@ struct t_user_pass { - char user[256]; - char pass[256]; + char user[256]; + char pass[256]; }; struct t_auth_info { - struct t_user_pass user_pass; - int session_opened; - int did_setcred; - struct pam_conv pamc; - pam_handle_t* ph; + struct t_user_pass user_pass; + int session_opened; + int did_setcred; + struct pam_conv pamc; + pam_handle_t *ph; }; /******************************************************************************/ static int DEFAULT_CC -verify_pam_conv(int num_msg, const struct pam_message** msg, - struct pam_response** resp, void* appdata_ptr) +verify_pam_conv(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) { - int i; - struct pam_response* reply; - struct t_user_pass* user_pass; + int i; + struct pam_response *reply; + struct t_user_pass *user_pass; - reply = g_malloc(sizeof(struct pam_response) * num_msg, 1); - for (i = 0; i < num_msg; i++) - { - switch (msg[i]->msg_style) + reply = g_malloc(sizeof(struct pam_response) * num_msg, 1); + + for (i = 0; i < num_msg; i++) { - case PAM_PROMPT_ECHO_ON: /* username */ - user_pass = appdata_ptr; - reply[i].resp = g_strdup(user_pass->user); - reply[i].resp_retcode = PAM_SUCCESS; - break; - case PAM_PROMPT_ECHO_OFF: /* password */ - user_pass = appdata_ptr; - reply[i].resp = g_strdup(user_pass->pass); - reply[i].resp_retcode = PAM_SUCCESS; - break; - default: - g_printf("unknown in verify_pam_conv\r\n"); - g_free(reply); - return PAM_CONV_ERR; + switch (msg[i]->msg_style) + { + case PAM_PROMPT_ECHO_ON: /* username */ + user_pass = appdata_ptr; + reply[i].resp = g_strdup(user_pass->user); + reply[i].resp_retcode = PAM_SUCCESS; + break; + case PAM_PROMPT_ECHO_OFF: /* password */ + user_pass = appdata_ptr; + reply[i].resp = g_strdup(user_pass->pass); + reply[i].resp_retcode = PAM_SUCCESS; + break; + default: + g_printf("unknown in verify_pam_conv\r\n"); + g_free(reply); + return PAM_CONV_ERR; + } } - } - *resp = reply; - return PAM_SUCCESS; + + *resp = reply; + return PAM_SUCCESS; } /******************************************************************************/ static void DEFAULT_CC -get_service_name(char* service_name) +get_service_name(char *service_name) { - service_name[0] = 0; - if (g_file_exist("/etc/pam.d/xrdp-sesman")) - { - g_strncpy(service_name, "xrdp-sesman", 255); - } - else - { - g_strncpy(service_name, "gdm", 255); - } + service_name[0] = 0; + + if (g_file_exist("/etc/pam.d/xrdp-sesman")) + { + g_strncpy(service_name, "xrdp-sesman", 255); + } + else + { + g_strncpy(service_name, "gdm", 255); + } } /******************************************************************************/ /* returns long, zero is no go */ long DEFAULT_CC -auth_userpass(char* user, char* pass) +auth_userpass(char *user, char *pass) { - int error; - struct t_auth_info* auth_info; - char service_name[256]; + int error; + struct t_auth_info *auth_info; + char service_name[256]; - get_service_name(service_name); - auth_info = g_malloc(sizeof(struct t_auth_info), 1); - g_strncpy(auth_info->user_pass.user, user, 255); - g_strncpy(auth_info->user_pass.pass, pass, 255); - auth_info->pamc.conv = &verify_pam_conv; - auth_info->pamc.appdata_ptr = &(auth_info->user_pass); - error = pam_start(service_name, 0, &(auth_info->pamc), &(auth_info->ph)); - if (error != PAM_SUCCESS) - { - g_printf("pam_start failed: %s\r\n", pam_strerror(auth_info->ph, error)); - g_free(auth_info); - return 0; - } - error = pam_authenticate(auth_info->ph, 0); - if (error != PAM_SUCCESS) - { - g_printf("pam_authenticate failed: %s\r\n", - pam_strerror(auth_info->ph, error)); - g_free(auth_info); - return 0; - } - error = pam_acct_mgmt(auth_info->ph, 0); - if (error != PAM_SUCCESS) - { - g_printf("pam_acct_mgmt failed: %s\r\n", - pam_strerror(auth_info->ph, error)); - g_free(auth_info); - return 0; - } - return (long)auth_info; + get_service_name(service_name); + auth_info = g_malloc(sizeof(struct t_auth_info), 1); + g_strncpy(auth_info->user_pass.user, user, 255); + g_strncpy(auth_info->user_pass.pass, pass, 255); + auth_info->pamc.conv = &verify_pam_conv; + auth_info->pamc.appdata_ptr = &(auth_info->user_pass); + error = pam_start(service_name, 0, &(auth_info->pamc), &(auth_info->ph)); + + if (error != PAM_SUCCESS) + { + g_printf("pam_start failed: %s\r\n", pam_strerror(auth_info->ph, error)); + g_free(auth_info); + return 0; + } + + error = pam_authenticate(auth_info->ph, 0); + + if (error != PAM_SUCCESS) + { + g_printf("pam_authenticate failed: %s\r\n", + pam_strerror(auth_info->ph, error)); + g_free(auth_info); + return 0; + } + + error = pam_acct_mgmt(auth_info->ph, 0); + + if (error != PAM_SUCCESS) + { + g_printf("pam_acct_mgmt failed: %s\r\n", + pam_strerror(auth_info->ph, error)); + g_free(auth_info); + return 0; + } + + return (long)auth_info; } /******************************************************************************/ @@ -141,34 +149,40 @@ auth_userpass(char* user, char* pass) int DEFAULT_CC auth_start_session(long in_val, int in_display) { - struct t_auth_info* auth_info; - int error; - char display[256]; + struct t_auth_info *auth_info; + int error; + char display[256]; - g_sprintf(display, ":%d", in_display); - auth_info = (struct t_auth_info*)in_val; - error = pam_set_item(auth_info->ph, PAM_TTY, display); - if (error != PAM_SUCCESS) - { - g_printf("pam_set_item failed: %s\r\n", pam_strerror(auth_info->ph, error)); - return 1; - } - error = pam_setcred(auth_info->ph, PAM_ESTABLISH_CRED); - if (error != PAM_SUCCESS) - { - g_printf("pam_setcred failed: %s\r\n", pam_strerror(auth_info->ph, error)); - return 1; - } - auth_info->did_setcred = 1; - error = pam_open_session(auth_info->ph, 0); - if (error != PAM_SUCCESS) - { - g_printf("pam_open_session failed: %s\r\n", - pam_strerror(auth_info->ph, error)); - return 1; - } - auth_info->session_opened = 1; - return 0; + g_sprintf(display, ":%d", in_display); + auth_info = (struct t_auth_info *)in_val; + error = pam_set_item(auth_info->ph, PAM_TTY, display); + + if (error != PAM_SUCCESS) + { + g_printf("pam_set_item failed: %s\r\n", pam_strerror(auth_info->ph, error)); + return 1; + } + + error = pam_setcred(auth_info->ph, PAM_ESTABLISH_CRED); + + if (error != PAM_SUCCESS) + { + g_printf("pam_setcred failed: %s\r\n", pam_strerror(auth_info->ph, error)); + return 1; + } + + auth_info->did_setcred = 1; + error = pam_open_session(auth_info->ph, 0); + + if (error != PAM_SUCCESS) + { + g_printf("pam_open_session failed: %s\r\n", + pam_strerror(auth_info->ph, error)); + return 1; + } + + auth_info->session_opened = 1; + return 0; } /******************************************************************************/ @@ -177,27 +191,31 @@ auth_start_session(long in_val, int in_display) int DEFAULT_CC auth_end(long in_val) { - struct t_auth_info* auth_info; + struct t_auth_info *auth_info; - auth_info = (struct t_auth_info*)in_val; - if (auth_info != 0) - { - if (auth_info->ph != 0) + auth_info = (struct t_auth_info *)in_val; + + if (auth_info != 0) { - if (auth_info->session_opened) - { - pam_close_session(auth_info->ph, 0); - } - if (auth_info->did_setcred) - { - pam_setcred(auth_info->ph, PAM_DELETE_CRED); - } - pam_end(auth_info->ph, PAM_SUCCESS); - auth_info->ph = 0; + if (auth_info->ph != 0) + { + if (auth_info->session_opened) + { + pam_close_session(auth_info->ph, 0); + } + + if (auth_info->did_setcred) + { + pam_setcred(auth_info->ph, PAM_DELETE_CRED); + } + + pam_end(auth_info->ph, PAM_SUCCESS); + auth_info->ph = 0; + } } - } - g_free(auth_info); - return 0; + + g_free(auth_info); + return 0; } /******************************************************************************/ @@ -206,33 +224,39 @@ auth_end(long in_val) int DEFAULT_CC auth_set_env(long in_val) { - struct t_auth_info* auth_info; - char** pam_envlist; - char** pam_env; - char item[256]; - char value[256]; - int eq_pos; + struct t_auth_info *auth_info; + char **pam_envlist; + char **pam_env; + char item[256]; + char value[256]; + int eq_pos; - auth_info = (struct t_auth_info*)in_val; - if (auth_info != 0) - { - /* export PAM environment */ - pam_envlist = pam_getenvlist(auth_info->ph); - if (pam_envlist != NULL) + auth_info = (struct t_auth_info *)in_val; + + if (auth_info != 0) { - for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) - { - eq_pos = g_pos(*pam_env, "="); - if (eq_pos >= 0 && eq_pos < 250) + /* export PAM environment */ + pam_envlist = pam_getenvlist(auth_info->ph); + + if (pam_envlist != NULL) { - g_strncpy(item, *pam_env, eq_pos); - g_strncpy(value, (*pam_env) + eq_pos + 1, 255); - g_setenv(item, value, 1); + for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) + { + eq_pos = g_pos(*pam_env, "="); + + if (eq_pos >= 0 && eq_pos < 250) + { + g_strncpy(item, *pam_env, eq_pos); + g_strncpy(value, (*pam_env) + eq_pos + 1, 255); + g_setenv(item, value, 1); + } + + g_free(*pam_env); + } + + g_free(pam_envlist); } - g_free(*pam_env); - } - g_free(pam_envlist); } - } - return 0; + + return 0; } diff --git a/sesman/verify_user_pam_userpass.c b/sesman/verify_user_pam_userpass.c index 0075afeb..9fa2d9e5 100644 --- a/sesman/verify_user_pam_userpass.c +++ b/sesman/verify_user_pam_userpass.c @@ -1,28 +1,27 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2008 -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /** * * @file verify_user_pam_userpass.c * @brief Authenticate user using pam_userpass module * @author Jay Sorg - * + * */ #include "arch.h" @@ -35,43 +34,52 @@ /******************************************************************************/ /* returns boolean */ int DEFAULT_CC -auth_userpass(char* user, char* pass) +auth_userpass(char *user, char *pass) { - pam_handle_t* pamh; - pam_userpass_t userpass; - struct pam_conv conv = {pam_userpass_conv, &userpass}; - const void* template1; - int status; + pam_handle_t *pamh; + pam_userpass_t userpass; + struct pam_conv conv = {pam_userpass_conv, &userpass}; + const void *template1; + int status; - userpass.user = user; - userpass.pass = pass; - if (pam_start(SERVICE, user, &conv, &pamh) != PAM_SUCCESS) - { - return 0; - } - status = pam_authenticate(pamh, 0); - if (status != PAM_SUCCESS) - { - pam_end(pamh, status); - return 0; - } - status = pam_acct_mgmt(pamh, 0); - if (status != PAM_SUCCESS) - { - pam_end(pamh, status); - return 0; - } - status = pam_get_item(pamh, PAM_USER, &template1); - if (status != PAM_SUCCESS) - { - pam_end(pamh, status); - return 0; - } - if (pam_end(pamh, PAM_SUCCESS) != PAM_SUCCESS) - { - return 0; - } - return 1; + userpass.user = user; + userpass.pass = pass; + + if (pam_start(SERVICE, user, &conv, &pamh) != PAM_SUCCESS) + { + return 0; + } + + status = pam_authenticate(pamh, 0); + + if (status != PAM_SUCCESS) + { + pam_end(pamh, status); + return 0; + } + + status = pam_acct_mgmt(pamh, 0); + + if (status != PAM_SUCCESS) + { + pam_end(pamh, status); + return 0; + } + + status = pam_get_item(pamh, PAM_USER, &template1); + + if (status != PAM_SUCCESS) + { + pam_end(pamh, status); + return 0; + } + + if (pam_end(pamh, PAM_SUCCESS) != PAM_SUCCESS) + { + return 0; + } + + return 1; } /******************************************************************************/ @@ -79,19 +87,19 @@ auth_userpass(char* user, char* pass) int DEFAULT_CC auth_start_session(void) { - return 0; + return 0; } /******************************************************************************/ int DEFAULT_CC auth_end(void) { - return 0; + return 0; } /******************************************************************************/ int DEFAULT_CC auth_set_env(void) { - return 0; + return 0; } diff --git a/tests/nx/client.sh b/tests/nx/client.sh deleted file mode 100755 index dc264560..00000000 --- a/tests/nx/client.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -xhost + - -if ! [ -d .nx ] -then - mkdir .nx -fi - -export LD_LIBRARY_PATH=$PWD - -./nxproxy -S nx/nx,session=session,id=jay,root=.nx,connect=127.0.0.1:10,delta=1,stream=1,data=1 - diff --git a/tests/nx/server.sh b/tests/nx/server.sh deleted file mode 100755 index df6e894b..00000000 --- a/tests/nx/server.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -export LD_LIBRARY_PATH=$PWD - -#./nxagent -R -bs -dpi 96 -geometry 1024x768 -noshpix -display nx/nx,link=adsl,delta=1,stream=1,data=1,a8taint=0,cache=4M:9 :9 - -# with cache -#./nxagent -D -bs -ac -dpi 96 -geometry 1024x768 -noshpix -display nx/nx,link=adsl,delta=1,stream=1,data=1,cache=4M:9 :9 - -# without cache -./nxagent -D -bs -ac -dpi 96 -geometry 1024x768 -noshpix -display nx/nx,link=adsl,delta=1,stream=1,data=1,cache=0M:9 :9 - diff --git a/tests/tcp_proxy/Makefile b/tests/tcp_proxy/Makefile new file mode 100644 index 00000000..d19b4818 --- /dev/null +++ b/tests/tcp_proxy/Makefile @@ -0,0 +1,12 @@ +CFLAGS = -O2 -Wall -I../../common +LDFLAGS = -Wl +OBJS = main.o ../../common/os_calls.o +LIBS = -ldl + +all: tcp_proxy + +tcp_proxy: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o tcp_proxy $(OBJS) $(LIBS) + +.PHONY clean: + rm -f $(OBJS) tcp_proxy diff --git a/tests/tcp_proxy/arch.h b/tests/tcp_proxy/arch.h deleted file mode 100644 index 2f3c51a2..00000000 --- a/tests/tcp_proxy/arch.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright (c) 2004-2007 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - -*/ - -#if !defined(ARCH_H) -#define ARCH_H - -/* check endianess */ -#if defined(__sparc__) || defined(__PPC__) || defined(__ppc__) -#define B_ENDIAN -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#define L_ENDIAN -#elif __BYTE_ORDER == __BIG_ENDIAN -#define B_ENDIAN -#endif -/* check if we need to align data */ -#if defined(__sparc__) || defined(__alpha__) || defined(__hppa__) || \ - defined(__AIX__) || defined(__PPC__) || defined(__mips__) || \ - defined(__ia64__) || defined(__ppc__) -#define NEED_ALIGN -#endif - -/* defines for thread creation factory functions */ -#if defined(_WIN32) -#define THREAD_RV unsigned long -#define THREAD_CC __stdcall -#else -#define THREAD_RV void* -#define THREAD_CC -#endif - -#if defined(__BORLANDC__) || defined(_WIN32) -#define APP_CC __fastcall -#define DEFAULT_CC __cdecl -#else -#define APP_CC -#define DEFAULT_CC -#endif - -#if defined(_WIN32) -#if defined(__BORLANDC__) -#define EXPORT_CC _export __cdecl -#else -#define EXPORT_CC -#endif -#else -#define EXPORT_CC -#endif - -typedef char ti8; -typedef unsigned char tui8; -typedef signed char tsi8; -typedef short ti16; -typedef unsigned short tui16; -typedef signed short tsi16; -typedef int ti32; -typedef unsigned int tui32; -typedef signed int tsi32; -typedef long tbus; - -#endif diff --git a/tests/tcp_proxy/main.c b/tests/tcp_proxy/main.c index 7bfc747e..301f79a5 100644 --- a/tests/tcp_proxy/main.c +++ b/tests/tcp_proxy/main.c @@ -1,15 +1,32 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -#include "os_calls.h" +#include -int g_loc_io_count = 0; // bytes read from local port -int g_rem_io_count = 0; // bytes read from remote port +int g_loc_io_count = 0; // bytes read from local port +int g_rem_io_count = 0; // bytes read from remote port static int g_terminated = 0; static char g_buf[1024 * 32]; /*****************************************************************************/ static int -main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) +main_loop(char *local_port, char *remote_ip, char *remote_port, int hexdump) { int lis_sck; int acc_sck; @@ -30,6 +47,7 @@ main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) lis_sck = g_tcp_socket(); g_tcp_set_non_blocking(lis_sck); error = g_tcp_bind(lis_sck, local_port); + if (error != 0) { g_writeln("bind failed"); @@ -39,6 +57,7 @@ main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) if (error == 0) { error = g_tcp_listen(lis_sck); + if (error == 0) { g_writeln("listening for connection"); @@ -51,6 +70,7 @@ main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) while ((!g_terminated) && (error == 0)) { acc_sck = g_tcp_accept(lis_sck); + if ((acc_sck == -1) && g_tcp_last_error_would_block(lis_sck)) { g_sleep(100); @@ -64,6 +84,7 @@ main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) break; } } + if (error == 0) { error = g_terminated; @@ -72,6 +93,7 @@ main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) /* stop listening */ g_tcp_close(lis_sck); lis_sck = 0; + if (error == 0) { g_writeln("got connection"); @@ -80,65 +102,79 @@ main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) /* connect outgoing socket */ con_sck = 0; + if (error == 0) { con_sck = g_tcp_socket(); g_tcp_set_non_blocking(con_sck); error = g_tcp_connect(con_sck, remote_ip, remote_port); + if ((error == -1) && g_tcp_last_error_would_block(con_sck)) { error = 0; i = 0; + while ((!g_tcp_can_send(con_sck, 100)) && (!g_terminated) && (i < 100)) { g_sleep(100); i++; } + if (i > 99) { g_writeln("timout connecting"); error = 1; } + if (g_terminated) { error = 1; } } + if ((error != 0) && (!g_terminated)) { g_writeln("error connecting to remote\r\n"); } } + while ((!g_terminated) && (error == 0)) { sel = g_tcp_select(con_sck, acc_sck); + if (sel == 0) { g_sleep(10); continue; } + if (sel & 1) { // can read from con_sck w/o blocking count = g_tcp_recv(con_sck, g_buf, 1024 * 16, 0); error = count < 1; + if (error == 0) { g_loc_io_count += count; con_to_acc += count; + if (hexdump) { g_writeln("from remove, the socket from connect"); g_hexdump(g_buf, count); } + #if 0 g_writeln("local_io_count: %d\tremote_io_count: %d", - g_loc_io_count, g_rem_io_count); + g_loc_io_count, g_rem_io_count); #endif sent = 0; + while ((sent < count) && (error == 0) && (!g_terminated)) { i = g_tcp_send(acc_sck, g_buf + sent, count - sent, 0); + if ((i == -1) && g_tcp_last_error_would_block(acc_sck)) { g_tcp_can_send(acc_sck, 1000); @@ -154,28 +190,34 @@ main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) } } } + if (sel & 2) { // can read from acc_sck w/o blocking count = g_tcp_recv(acc_sck, g_buf, 1024 * 16, 0); error = count < 1; + if (error == 0) { g_rem_io_count += count; acc_to_con += count; + if (hexdump) { g_writeln("from accepted, the socket from accept"); g_hexdump(g_buf, count); } + #if 0 g_writeln("local_io_count: %d\tremote_io_count: %d", - g_loc_io_count, g_rem_io_count); + g_loc_io_count, g_rem_io_count); #endif sent = 0; + while ((sent < count) && (error == 0) && (!g_terminated)) { i = g_tcp_send(con_sck, g_buf + sent, count - sent, 0); + if ((i == -1) && g_tcp_last_error_would_block(con_sck)) { g_tcp_can_send(con_sck, 1000); @@ -192,6 +234,7 @@ main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) } } } + g_tcp_close(lis_sck); g_tcp_close(con_sck); g_tcp_close(acc_sck); @@ -221,7 +264,7 @@ proxy_shutdown(int sig) void clear_counters(int sig) { - g_writeln("cleared counters at: local_io_count: %d remote_io_count: %d", + g_writeln("cleared counters at: local_io_count: %d remote_io_count: %d", g_loc_io_count, g_rem_io_count); g_loc_io_count = 0; g_rem_io_count = 0; @@ -229,7 +272,7 @@ clear_counters(int sig) /*****************************************************************************/ int -main(int argc, char** argv) +main(int argc, char **argv) { int dump; @@ -238,11 +281,13 @@ main(int argc, char** argv) usage(); return 0; } - g_init(); - g_signal(2, proxy_shutdown); /* SIGINT */ - g_signal(9, proxy_shutdown); /* SIGKILL */ - g_signal(10, clear_counters);/* SIGUSR1*/ - g_signal(15, proxy_shutdown);/* SIGTERM */ + + g_init("tcp_proxy"); + g_signal_user_interrupt(proxy_shutdown); /* SIGINT */ + g_signal_kill(proxy_shutdown); /* SIGKILL */ + g_signal_usr1(clear_counters); /* SIGUSR1 */ + g_signal_terminate(proxy_shutdown); /* SIGTERM */ + if (argc < 5) { while (!g_terminated) @@ -255,11 +300,13 @@ main(int argc, char** argv) else { dump = g_strcasecmp(argv[4], "dump") == 0; + while (!g_terminated) { main_loop(argv[1], argv[2], argv[3], dump); } } + g_deinit(); return 0; } diff --git a/tests/tcp_proxy/os_calls.c b/tests/tcp_proxy/os_calls.c deleted file mode 100644 index b17856bc..00000000 --- a/tests/tcp_proxy/os_calls.c +++ /dev/null @@ -1,1449 +0,0 @@ -/* - Copyright (c) 2004-2007 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - generic operating system calls - - put all the os / arch define in here you want -*/ - -#if defined(_WIN32) -#include -#include -#else -/* fix for solaris 10 with gcc 3.3.2 problem */ -#if defined(sun) || defined(__sun) -#define ctid_t id_t -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#include -#include -#include -#include - -#include "os_calls.h" -#include "arch.h" - -/* for clearenv() */ -#if defined(_WIN32) -#else -extern char** environ; -#endif - -/* for solaris */ -#if !defined(PF_LOCAL) -#define PF_LOCAL AF_UNIX -#endif -#if !defined(INADDR_NONE) -#define INADDR_NONE ((unsigned long)-1) -#endif - -/*****************************************************************************/ -void APP_CC -g_init(void) -{ - #if defined(_WIN32) - WSADATA wsadata; - - WSAStartup(2, &wsadata); - #endif -} - - -/*****************************************************************************/ -void APP_CC -g_deinit(void) -{ - #if defined(_WIN32) - WSACleanup(); - #endif -} - - -/*****************************************************************************/ -/* allocate memory, returns a pointer to it, size bytes are allocated, - if zero is non zero, each byte will be set to zero */ -void* APP_CC -g_malloc(int size, int zero) -{ - char* rv; - - rv = (char*)malloc(size); - if (zero) - { - memset(rv, 0, size); - } - return rv; -} - - -/*****************************************************************************/ -/* free the memory pointed to by ptr, ptr can be zero */ -void APP_CC -g_free(void* ptr) -{ - if (ptr != 0) - { - free(ptr); - } -} - - -/*****************************************************************************/ -/* output text to stdout, try to use g_write / g_writeln instead to avoid - linux / windows EOL problems */ -void DEFAULT_CC -g_printf(const char* format, ...) -{ - va_list ap; - - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); -} - - -/*****************************************************************************/ -void DEFAULT_CC -g_sprintf(char* dest, const char* format, ...) -{ - va_list ap; - - va_start(ap, format); - vsprintf(dest, format, ap); - va_end(ap); -} - - -/*****************************************************************************/ -void DEFAULT_CC -g_snprintf(char* dest, int len, const char* format, ...) -{ - va_list ap; - - va_start(ap, format); - vsnprintf(dest, len, format, ap); - va_end(ap); -} - - -/*****************************************************************************/ -void DEFAULT_CC -g_writeln(const char* format, ...) -{ - va_list ap; - - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); - #if defined(_WIN32) - g_printf("\r\n"); - #else - g_printf("\n"); - #endif -} - - -/*****************************************************************************/ -void DEFAULT_CC -g_write(const char* format, ...) -{ - va_list ap; - - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); -} - - -/*****************************************************************************/ -/* produce a hex dump */ -void APP_CC -g_hexdump(char* p, int len) -{ - unsigned char* line; - int i; - int thisline; - int offset; - - line = (unsigned char*)p; - offset = 0; - while (offset < len) - { - g_printf("%04x ", offset); - thisline = len - offset; - if (thisline > 16) - { - thisline = 16; - } - for (i = 0; i < thisline; i++) - { - g_printf("%02x ", line[i]); - } - for (; i < 16; i++) - { - g_printf(" "); - } - for (i = 0; i < thisline; i++) - { - g_printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); - } - g_writeln(""); - offset += thisline; - line += thisline; - } -} - - -/*****************************************************************************/ -void APP_CC -g_memset(void* ptr, int val, int size) -{ - memset(ptr, val, size); -} - - -/*****************************************************************************/ -void APP_CC -g_memcpy(void* d_ptr, const void* s_ptr, int size) -{ - memcpy(d_ptr, s_ptr, size); -} - - -/*****************************************************************************/ -int APP_CC -g_getchar(void) -{ - return getchar(); -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_set_no_delay(int sck) -{ - int i; - - i = 1; - #if defined(_WIN32) - setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (char*)&i, sizeof(i)); - #else - setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (void*)&i, sizeof(i)); - #endif - return 0; -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_socket(void) -{ - int rv; - int i; - - rv = socket(PF_INET, SOCK_STREAM, 0); - #if defined(_WIN32) - i = 1; - setsockopt(rv, IPPROTO_TCP, TCP_NODELAY, (char*)&i, sizeof(i)); - i = 1; - setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof(i)); - i = 8192 * 2; - setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char*)&i, sizeof(i)); - #else - i = 1; - setsockopt(rv, IPPROTO_TCP, TCP_NODELAY, (void*)&i, sizeof(i)); - i = 1; - setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (void*)&i, sizeof(i)); - i = 8192 * 2; - setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (void*)&i, sizeof(i)); - #endif - return rv; -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_local_socket(void) -{ - #if defined(_WIN32) - return 0; - #else - return socket(PF_LOCAL, SOCK_STREAM, 0); - #endif -} - - -/*****************************************************************************/ -void APP_CC -g_tcp_close(int sck) -{ - if (sck == 0) - { - return; - } - shutdown(sck, 2); - #if defined(_WIN32) - closesocket(sck); - #else - close(sck); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_connect(int sck, const char* address, const char* port) -{ - struct sockaddr_in s; - struct hostent* h; - - g_memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons(atoi(port)); - s.sin_addr.s_addr = inet_addr(address); - if (s.sin_addr.s_addr == INADDR_NONE) - { - h = gethostbyname(address); - if (h != 0) - { - if (h->h_name != 0) - { - if (h->h_addr_list != 0) - { - if ((*(h->h_addr_list)) != 0) - { - s.sin_addr.s_addr = *((int*)(*(h->h_addr_list))); - } - } - } - } - } - return connect(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_set_non_blocking(int sck) -{ - unsigned long i; - - #if defined(_WIN32) - i = 1; - ioctlsocket(sck, FIONBIO, &i); - #else - i = fcntl(sck, F_GETFL); - i = i | O_NONBLOCK; - fcntl(sck, F_SETFL, i); - #endif - return 0; -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_bind(int sck, char* port) -{ - struct sockaddr_in s; - - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons(atoi(port)); - s.sin_addr.s_addr = INADDR_ANY; - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_local_bind(int sck, char* port) -{ - #if defined(_WIN32) - return -1; - #else - struct sockaddr_un s; - - memset(&s, 0, sizeof(struct sockaddr_un)); - s.sun_family = AF_UNIX; - strcpy(s.sun_path, port); - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_un)); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_listen(int sck) -{ - return listen(sck, 2); -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_accept(int sck) -{ - struct sockaddr_in s; - #if defined(_WIN32) - signed int i; - #else - unsigned int i; - #endif - - i = sizeof(struct sockaddr_in); - memset(&s, 0, i); - return accept(sck, (struct sockaddr*)&s, &i); -} - - -/*****************************************************************************/ -void APP_CC -g_sleep(int msecs) -{ - #if defined(_WIN32) - Sleep(msecs); - #else - usleep(msecs * 1000); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_last_error_would_block(int sck) -{ - #if defined(_WIN32) - return WSAGetLastError() == WSAEWOULDBLOCK; - #else - return (errno == EWOULDBLOCK) || (errno == EINPROGRESS); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_recv(int sck, void* ptr, int len, int flags) -{ - #if defined(_WIN32) - return recv(sck, (char*)ptr, len, flags); - #else - return recv(sck, ptr, len, flags); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_send(int sck, const void* ptr, int len, int flags) -{ - #if defined(_WIN32) - return send(sck, (const char*)ptr, len, flags); - #else - return send(sck, ptr, len, flags); - #endif -} - - -/*****************************************************************************/ -/* wait 'millis' milliseconds for the socket to be able to write */ -/* returns boolean */ -int APP_CC -g_tcp_can_send(int sck, int millis) -{ - fd_set wfds; - struct timeval time; - int rv; - - time.tv_sec = millis / 1000; - time.tv_usec = (millis * 1000) % 1000000; - FD_ZERO(&wfds); - if (sck > 0) - { - FD_SET(((unsigned int)sck), &wfds); - rv = select(sck + 1, 0, &wfds, 0, &time); - if (rv > 0) - { - return 1; - } - } - return 0; -} - - -/*****************************************************************************/ -/* wait 'millis' milliseconds for the socket to be able to receive */ -/* returns boolean */ -int APP_CC -g_tcp_can_recv(int sck, int millis) -{ - fd_set rfds; - struct timeval time; - int rv; - - time.tv_sec = millis / 1000; - time.tv_usec = (millis * 1000) % 1000000; - FD_ZERO(&rfds); - if (sck > 0) - { - FD_SET(((unsigned int)sck), &rfds); - rv = select(sck + 1, &rfds, 0, 0, &time); - if (rv > 0) - { - return 1; - } - } - return 0; -} - - -/*****************************************************************************/ -int APP_CC -g_tcp_select(int sck1, int sck2) -{ - fd_set rfds; - struct timeval time; - int max; - int rv; - - time.tv_sec = 0; - time.tv_usec = 0; - FD_ZERO(&rfds); - if (sck1 > 0) - { - FD_SET(((unsigned int)sck1), &rfds); - } - if (sck2 > 0) - { - FD_SET(((unsigned int)sck2), &rfds); - } - max = sck1; - if (sck2 > max) - { - max = sck2; - } - rv = select(max + 1, &rfds, 0, 0, &time); - if (rv > 0) - { - rv = 0; - if (FD_ISSET(((unsigned int)sck1), &rfds)) - { - rv = rv | 1; - } - if (FD_ISSET(((unsigned int)sck2), &rfds)) - { - rv = rv | 2; - } - } - else - { - rv = 0; - } - return rv; -} - - -/*****************************************************************************/ -void APP_CC -g_random(char* data, int len) -{ - #if defined(_WIN32) - memset(data, 0x44, len); - #else - int fd; - - memset(data, 0x44, len); - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) - { - fd = open("/dev/random", O_RDONLY); - } - if (fd != -1) - { - read(fd, data, len); - close(fd); - } - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_abs(int i) -{ - return abs(i); -} - - -/*****************************************************************************/ -int APP_CC -g_memcmp(const void* s1, const void* s2, int len) -{ - return memcmp(s1, s2, len); -} - - -/*****************************************************************************/ -/* returns -1 on error, else return handle or file descriptor */ -int APP_CC -g_file_open(const char* file_name) -{ - #if defined(_WIN32) - return (int)CreateFile(file_name, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - #else - int rv; - - rv = open(file_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - if (rv == -1) - { - /* can't open read / write, try to open read only */ - rv = open(file_name, O_RDONLY); - } - return rv; - #endif -} - - -/*****************************************************************************/ -/* returns error, always 0 */ -int APP_CC -g_file_close(int fd) -{ - #if defined(_WIN32) - CloseHandle((HANDLE)fd); - #else - close(fd); - #endif - return 0; -} - - -/*****************************************************************************/ -/* read from file, returns the number of bytes read or -1 on error */ -int APP_CC -g_file_read(int fd, char* ptr, int len) -{ - #if defined(_WIN32) - if (ReadFile((HANDLE)fd, (LPVOID)ptr, (DWORD)len, (LPDWORD)&len, 0)) - { - return len; - } - else - { - return -1; - } - #else - return read(fd, ptr, len); - #endif -} - - -/*****************************************************************************/ -/* write to file, returns the number of bytes writen or -1 on error */ -int APP_CC -g_file_write(int fd, char* ptr, int len) -{ - #if defined(_WIN32) - if (WriteFile((HANDLE)fd, (LPVOID)ptr, (DWORD)len, (LPDWORD)&len, 0)) - { - return len; - } - else - { - return -1; - } - #else - return write(fd, ptr, len); - #endif -} - - -/*****************************************************************************/ -/* move file pointer, returns offset on success, -1 on failure */ -int APP_CC -g_file_seek(int fd, int offset) -{ - #if defined(_WIN32) - int rv; - - rv = (int)SetFilePointer((HANDLE)fd, offset, 0, FILE_BEGIN); - if (rv == (int)INVALID_SET_FILE_POINTER) - { - return -1; - } - else - { - return rv; - } - #else - return (int)lseek(fd, offset, SEEK_SET); - #endif -} - - -/*****************************************************************************/ -/* do a write lock on a file */ -/* return boolean */ -int APP_CC -g_file_lock(int fd, int start, int len) -{ - #if defined(_WIN32) - return LockFile((HANDLE)fd, start, 0, len, 0); - #else - 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 0; - } - return 1; - #endif -} - - -/*****************************************************************************/ -/* returns error, always zero */ -int APP_CC -g_set_file_rights(const char* filename, int read, int write) -{ - #if defined(_WIN32) - return 0; - #else - int flags; - - flags = read ? S_IRUSR : 0; - flags |= write ? S_IWUSR : 0; - chmod(filename, flags); - return 0; - #endif -} - - -/*****************************************************************************/ -/* returns error */ -int APP_CC -g_chmod_hex(const char* filename, int flags) -{ - #if defined(_WIN32) - return 0; - #else - int fl; - - fl = 0; - fl |= (flags & 0x4000) ? S_ISUID : 0; - fl |= (flags & 0x2000) ? S_ISGID : 0; - fl |= (flags & 0x1000) ? S_ISVTX : 0; - fl |= (flags & 0x0400) ? S_IRUSR : 0; - fl |= (flags & 0x0200) ? S_IWUSR : 0; - fl |= (flags & 0x0100) ? S_IXUSR : 0; - fl |= (flags & 0x0040) ? S_IRGRP : 0; - fl |= (flags & 0x0020) ? S_IWGRP : 0; - fl |= (flags & 0x0010) ? S_IXGRP : 0; - fl |= (flags & 0x0004) ? S_IROTH : 0; - fl |= (flags & 0x0002) ? S_IWOTH : 0; - fl |= (flags & 0x0001) ? S_IXOTH : 0; - return chmod(filename, fl); - #endif -} - - -/*****************************************************************************/ -/* returns error, always zero */ -int APP_CC -g_mkdir(const char* dirname) -{ - #if defined(_WIN32) - return 0; - #else - mkdir(dirname, S_IRWXU); - return 0; - #endif -} - - -/*****************************************************************************/ -/* gets the current working directory and puts up to maxlen chars in - dirname - always returns 0 */ -char* APP_CC -g_get_current_dir(char* dirname, int maxlen) -{ - #if defined(_WIN32) - GetCurrentDirectory(maxlen, dirname); - return 0; - #else - getcwd(dirname, maxlen); - return 0; - #endif -} - - -/*****************************************************************************/ -/* returns error, zero on success and -1 on failure */ -int APP_CC -g_set_current_dir(char* dirname) -{ - #if defined(_WIN32) - if (SetCurrentDirectory(dirname)) - { - return 0; - } - else - { - return -1; - } - #else - return chdir(dirname); - #endif -} - - -/*****************************************************************************/ -/* returns boolean, non zero if the file exists */ -int APP_CC -g_file_exist(const char* filename) -{ - #if defined(_WIN32) - return 0; // use FileAge(filename) <> -1 - #else - return access(filename, F_OK) == 0; - #endif -} - - -/*****************************************************************************/ -/* returns boolean, non zero if the directory exists */ -int APP_CC -g_directory_exist(const char* dirname) -{ - #if defined(_WIN32) - return 0; // use GetFileAttributes and check return value - // is not -1 and FILE_ATTRIBUT_DIRECTORY bit is set - #else - struct stat st; - - if (stat(dirname, &st) == 0) - { - return S_ISDIR(st.st_mode); - } - else - { - return 0; - } - #endif -} - - -/*****************************************************************************/ -/* returns boolean */ -int APP_CC -g_create_dir(const char* dirname) -{ - #if defined(_WIN32) - // test this - return CreateDirectory(dirname, 0); - #else - return mkdir(dirname, (mode_t)-1) == 0; - #endif -} - - -/*****************************************************************************/ -/* returns boolean */ -int APP_CC -g_remove_dir(const char* dirname) -{ - #if defined(_WIN32) - // test this - return RemoveDirectory(dirname); - #else - return rmdir(dirname) == 0; - #endif -} - - -/*****************************************************************************/ -/* returns non zero if the file was deleted */ -int APP_CC -g_file_delete(const char* filename) -{ - #if defined(_WIN32) - return DeleteFile(filename); - #else - return unlink(filename) != -1; - #endif -} - - -/*****************************************************************************/ -/* returns length of text */ -int APP_CC -g_strlen(const char* text) -{ - if (text == 0) - { - return 0; - } - return strlen(text); -} - - -/*****************************************************************************/ -/* returns dest */ -char* APP_CC -g_strcpy(char* dest, const char* src) -{ - if (src == 0 && dest != 0) - { - dest[0] = 0; - return dest; - } - if (dest == 0 || src == 0) - { - return 0; - } - return strcpy(dest, src); -} - - -/*****************************************************************************/ -/* returns dest */ -char* APP_CC -g_strncpy(char* dest, const char* src, int len) -{ - char* rv; - - if (src == 0 && dest != 0) - { - dest[0] = 0; - return dest; - } - if (dest == 0 || src == 0) - { - return 0; - } - rv = strncpy(dest, src, len); - dest[len] = 0; - return rv; -} - - -/*****************************************************************************/ -/* returns dest */ -char* APP_CC -g_strcat(char* dest, const char* src) -{ - if (dest == 0 || src == 0) - { - return dest; - } - return strcat(dest, src); -} - - -/*****************************************************************************/ -/* if in = 0, return 0 else return newly alloced copy of in */ -char* APP_CC -g_strdup(const char* in) -{ - int len; - char* p; - - if (in == 0) - { - return 0; - } - len = g_strlen(in); - p = (char*)g_malloc(len + 1, 0); - g_strcpy(p, in); - return p; -} - - -/*****************************************************************************/ -int APP_CC -g_strcmp(const char* c1, const char* c2) -{ - return strcmp(c1, c2); -} - - -/*****************************************************************************/ -int APP_CC -g_strncmp(const char* c1, const char* c2, int len) -{ - return strncmp(c1, c2, len); -} - - -/*****************************************************************************/ -int APP_CC -g_strcasecmp(const char* c1, const char* c2) -{ - #if defined(_WIN32) - return stricmp(c1, c2); - #else - return strcasecmp(c1, c2); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_strncasecmp(const char* c1, const char* c2, int len) -{ - #if defined(_WIN32) - return strnicmp(c1, c2, len); - #else - return strncasecmp(c1, c2, len); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_atoi(char* str) -{ - return atoi(str); -} - - -/*****************************************************************************/ -int APP_CC -g_pos(char* str, const char* to_find) -{ - char* pp; - - pp = strstr(str, to_find); - if (pp == 0) - { - return -1; - } - return (pp - str); -} - - -/*****************************************************************************/ -long APP_CC -g_load_library(char* in) -{ - #if defined(_WIN32) - return (long)LoadLibrary(in); - #else - return (long)dlopen(in, RTLD_LOCAL | RTLD_LAZY); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_free_library(long lib) -{ - if (lib == 0) - { - return 0; - } - #if defined(_WIN32) - return FreeLibrary((HMODULE)lib); - #else - return dlclose((void*)lib); - #endif -} - - -/*****************************************************************************/ -/* returns NULL if not found */ -void* APP_CC -g_get_proc_address(long lib, const char* name) -{ - if (lib == 0) - { - return 0; - } - #if defined(_WIN32) - return GetProcAddress((HMODULE)lib, name); - #else - return dlsym((void*)lib, name); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_system(char* aexec) -{ - #if defined(_WIN32) - return 0; - #else - return system(aexec); - #endif -} - - -/*****************************************************************************/ -char* APP_CC -g_get_strerror(void) -{ - #if defined(_WIN32) - return 0; - #else - return strerror(errno); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_execvp(const char* p1, char* args[]) -{ - #if defined(_WIN32) - return 0; - #else - return execvp(p1, args); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_execlp3(const char* a1, const char* a2, const char* a3) -{ - #if defined(_WIN32) - return 0; - #else - return execlp(a1, a2, a3, (void*)0); - #endif -} - - -/*****************************************************************************/ -void APP_CC -g_signal(int sig_num, void (*func)(int)) -{ - #if defined(_WIN32) - #else - signal(sig_num, func); - #endif -} - - -/*****************************************************************************/ -void APP_CC -g_signal_child_stop(void (*func)(int)) -{ - #if defined(_WIN32) - #else - signal(SIGCHLD, func); - #endif -} - - -/*****************************************************************************/ -void APP_CC -g_unset_signals(void) -{ - #if defined(_WIN32) - #else - sigset_t mask; - - sigemptyset(&mask); - sigprocmask(SIG_SETMASK, &mask, NULL); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_fork(void) -{ - #if defined(_WIN32) - return 0; - #else - return fork(); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_setgid(int pid) -{ - #if defined(_WIN32) - return 0; - #else - return setgid(pid); - #endif -} - - -/*****************************************************************************/ -/* returns error, zero is success, non zero is error */ -int APP_CC -g_initgroups(const char* user, int gid) -{ - #if defined(_WIN32) - return 0; - #else - return initgroups(user ,gid); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_setuid(int pid) -{ - #if defined(_WIN32) - return 0; - #else - return setuid(pid); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_waitchild(void) -{ - #if defined(_WIN32) - return 0; - #else - int wstat; - - return waitpid(0, &wstat, WNOHANG); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_waitpid(int pid) -{ - #if defined(_WIN32) - return 0; - #else - return waitpid(pid, 0, 0); - #endif -} - - -/*****************************************************************************/ -void APP_CC -g_clearenv(void) -{ - #if defined(_WIN32) - #else - environ = 0; - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_setenv(const char* name, const char* value, int rewrite) -{ - #if defined(_WIN32) - return 0; - #else - return setenv(name, value, rewrite); - #endif -} - - -/*****************************************************************************/ -char* APP_CC -g_getenv(const char* name) -{ - #if defined(_WIN32) - return 0; - #else - return getenv(name); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_exit(int exit_code) -{ - _exit(exit_code); - return 0; -} - - -/*****************************************************************************/ -int APP_CC -g_getpid(void) -{ - #if defined(_WIN32) - return 0; - #else - return getpid(); - #endif -} - - -/*****************************************************************************/ -int APP_CC -g_sigterm(int pid) -{ - #if defined(_WIN32) - return 0; - #else - return kill(pid, SIGTERM); - #endif -} - - -/*****************************************************************************/ -/* returns 0 if ok */ -int APP_CC -g_getuser_info(const char* username, int* gid, int* uid, char* shell, -char* dir, char* gecos) -{ - #if defined(_WIN32) - return 1; - #else - struct passwd* pwd_1; - - pwd_1 = getpwnam(username); - if (pwd_1 != 0) - { - if (gid != 0) - { - *gid = pwd_1->pw_gid; - } - if (uid != 0) - { - *uid = pwd_1->pw_uid; - } - if (dir != 0) - { - g_strcpy(dir, pwd_1->pw_dir); - } - if (shell != 0) - { - g_strcpy(shell, pwd_1->pw_shell); - } - if (gecos != 0) - { - g_strcpy(gecos, pwd_1->pw_gecos); - } - return 0; - } - return 1; - #endif -} - - -/*****************************************************************************/ -/* returns 0 if ok */ -int APP_CC -g_getgroup_info(const char* groupname, int* gid) -{ - #if defined(_WIN32) - return 1; - #else - struct group* g; - - g = getgrnam(groupname); - if (g != 0) - { - if (gid != 0) - { - *gid = g->gr_gid; - } - return 0; - } - return 1; - #endif -} - - -/*****************************************************************************/ -/* returns error */ -/* if zero is returned, then ok is set */ -int APP_CC -g_check_user_in_group(const char* username, int gid, int* ok) -{ - #if defined(_WIN32) - return 1; - #else - struct group* groups; - int i; - - groups = getgrgid(gid); - if (groups == 0) - { - return 1; - } - *ok = 0; - i = 0; - while (0 != groups->gr_mem[i]) - { - if (0 == g_strcmp(groups->gr_mem[i], username)) - { - *ok = 1; - break; - } - i++; - } - return 0; - #endif -} - - -/*****************************************************************************/ -/* returns the time since the Epoch (00:00:00 UTC, January 1, 1970), - measured in seconds. */ -int APP_CC -g_time1(void) -{ - #if defined(_WIN32) - return GetTickCount() / 1000; - #else - return time(0); - #endif -} diff --git a/tests/tcp_proxy/os_calls.h b/tests/tcp_proxy/os_calls.h deleted file mode 100644 index 768cc38c..00000000 --- a/tests/tcp_proxy/os_calls.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - Copyright (c) 2004-2007 Jay Sorg - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - generic operating system calls -*/ - -#if !defined(OS_CALLS_H) -#define OS_CALLS_H - -#include "arch.h" - -void APP_CC -g_init(void); -void APP_CC -g_deinit(void); -void* APP_CC -g_malloc(int size, int zero); -void APP_CC -g_free(void* ptr); -void DEFAULT_CC -g_printf(const char *format, ...); -void DEFAULT_CC -g_sprintf(char* dest, const char* format, ...); -void DEFAULT_CC -g_snprintf(char* dest, int len, const char* format, ...); -void DEFAULT_CC -g_writeln(const char* format, ...); -void DEFAULT_CC -g_write(const char* format, ...); -void APP_CC -g_hexdump(char* p, int len); -void APP_CC -g_memset(void* ptr, int val, int size); -void APP_CC -g_memcpy(void* d_ptr, const void* s_ptr, int size); -int APP_CC -g_getchar(void); -int APP_CC -g_tcp_set_no_delay(int sck); -int APP_CC -g_tcp_socket(void); -int APP_CC -g_tcp_local_socket(void); -void APP_CC -g_tcp_close(int sck); -int APP_CC -g_tcp_connect(int sck, const char* address, const char* port); -int APP_CC -g_tcp_force_send(int sck, char* data, int len); -int APP_CC -g_tcp_force_recv(int sck, char* data, int len); -int APP_CC -g_tcp_set_non_blocking(int sck); -int APP_CC -g_tcp_bind(int sck, char* port); -int APP_CC -g_tcp_local_bind(int sck, char* port); -int APP_CC -g_tcp_listen(int sck); -int APP_CC -g_tcp_accept(int sck); -int APP_CC -g_tcp_recv(int sck, void* ptr, int len, int flags); -int APP_CC -g_tcp_send(int sck, const void* ptr, int len, int flags); -int APP_CC -g_tcp_last_error_would_block(int sck); -int APP_CC -g_tcp_can_send(int sck, int millis); -int APP_CC -g_tcp_can_recv(int sck, int millis); -int APP_CC -g_tcp_select(int sck1, int sck2); -void APP_CC -g_sleep(int msecs); -void APP_CC -g_random(char* data, int len); -int APP_CC -g_abs(int i); -int APP_CC -g_memcmp(const void* s1, const void* s2, int len); -int APP_CC -g_file_open(const char* file_name); -int APP_CC -g_file_close(int fd); -int APP_CC -g_file_read(int fd, char* ptr, int len); -int APP_CC -g_file_write(int fd, char* ptr, int len); -int APP_CC -g_file_seek(int fd, int offset); -int APP_CC -g_file_lock(int fd, int start, int len); -int APP_CC -g_set_file_rights(const char* filename, int read, int write); -int APP_CC -g_chmod_hex(const char* filename, int flags); -int APP_CC -g_mkdir(const char* dirname); -char* APP_CC -g_get_current_dir(char* dirname, int maxlen); -int APP_CC -g_set_current_dir(char* dirname); -int APP_CC -g_file_exist(const char* filename); -int APP_CC -g_directory_exist(const char* dirname); -int APP_CC -g_create_dir(const char* dirname); -int APP_CC -g_remove_dir(const char* dirname); -int APP_CC -g_file_delete(const char* filename); -int APP_CC -g_strlen(const char* text); -char* APP_CC -g_strcpy(char* dest, const char* src); -char* APP_CC -g_strncpy(char* dest, const char* src, int len); -char* APP_CC -g_strcat(char* dest, const char* src); -char* APP_CC -g_strdup(const char* in); -int APP_CC -g_strcmp(const char* c1, const char* c2); -int APP_CC -g_strncmp(const char* c1, const char* c2, int len); -int APP_CC -g_strcasecmp(const char* c1, const char* c2); -int APP_CC -g_strncasecmp(const char* c1, const char* c2, int len); -int APP_CC -g_atoi(char* str); -int APP_CC -g_pos(char* str, const char* to_find); -long APP_CC -g_load_library(char* in); -int APP_CC -g_free_library(long lib); -void* APP_CC -g_get_proc_address(long lib, const char* name); -int APP_CC -g_system(char* aexec); -char* APP_CC -g_get_strerror(void); -int APP_CC -g_execvp(const char* p1, char* args[]); -int APP_CC -g_execlp3(const char* a1, const char* a2, const char* a3); -void APP_CC -g_signal(int sig_num, void (*func)(int)); -void APP_CC -g_signal_child_stop(void (*func)(int)); -void APP_CC -g_unset_signals(void); -int APP_CC -g_fork(void); -int APP_CC -g_setgid(int pid); -int APP_CC -g_initgroups(const char* user, int gid); -int APP_CC -g_setuid(int pid); -int APP_CC -g_waitchild(void); -int APP_CC -g_waitpid(int pid); -void APP_CC -g_clearenv(void); -int APP_CC -g_setenv(const char* name, const char* value, int rewrite); -char* APP_CC -g_getenv(const char* name); -int APP_CC -g_exit(int exit_code); -int APP_CC -g_getpid(void); -int APP_CC -g_sigterm(int pid); -int APP_CC -g_getuser_info(const char* username, int* gid, int* uid, char* shell, - char* dir, char* gecos); -int APP_CC -g_getgroup_info(const char* groupname, int* gid); -int APP_CC -g_check_user_in_group(const char* username, int gid, int* ok); -int APP_CC -g_time1(void); - -#endif diff --git a/tests/xdemo/README.txt b/tests/xdemo/README.txt deleted file mode 100644 index 52bda08c..00000000 --- a/tests/xdemo/README.txt +++ /dev/null @@ -1,3 +0,0 @@ - -this is a project to develope a program to test xwindows - diff --git a/tests/xdemo/bmp_parser.c b/tests/xdemo/bmp_parser.c deleted file mode 100644 index 9d3e43c8..00000000 --- a/tests/xdemo/bmp_parser.c +++ /dev/null @@ -1,204 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "common.h" - -// multi byte values are stored in little endian - -struct bmp_magic -{ - char magic[2]; -}; - -struct bmp_hdr -{ - uint32_t size; // file size in bytes - uint16_t reserved1; - uint16_t reserved2; - uint32_t offset; // offset to image data, in bytes -}; - -struct dib_hdr -{ - uint32_t hdr_size; - int32_t width; - int32_t height; - uint16_t nplanes; - uint16_t bpp; - uint32_t compress_type; - uint32_t image_size; - int32_t hres; - int32_t vres; - uint32_t ncolors; - uint32_t nimpcolors; -}; - -// forward declarations -int parse_bmp(char *filename, struct pic_info *pic_info); -int parse_bmp_24(struct bmp_hdr *bmp_hdr, struct dib_hdr *dib_hdr, int fd, struct pic_info *pic_info); - -int parse_bmp(char *filename, struct pic_info *pic_info) -{ - int got_magic; - int fd; - int rval; - - struct bmp_magic magic; - struct bmp_hdr bmp_hdr; - struct dib_hdr dib_hdr; - - if ((fd = open(filename, O_RDONLY)) < 0) { - printf("error opeing %s\n", filename); - return -1; - } - - // read BMP magic... - if ((rval = read(fd, magic.magic, 2)) != 2) { - fprintf(stderr, "error reading BMP signature from file %s\n", filename); - return -1; - } - - got_magic = 0; - - // ...and confirm that this is indeed a BMP file - if ((magic.magic[0] == 'B') && (magic.magic[1] == 'M')) { - // BM – Windows 3.1x, 95, NT, ... etc - got_magic = 1; - } - else if ((magic.magic[0] == 'B') && (magic.magic[1] == 'A')) { - // BA – OS/2 struct Bitmap Array - got_magic = 1; - } - else if ((magic.magic[0] == 'C') && (magic.magic[1] == 'I')) { - // CI – OS/2 struct Color Icon - got_magic = 1; - } - else if ((magic.magic[0] == 'C') && (magic.magic[1] == 'P')) { - // CP – OS/2 const Color Pointer - got_magic = 1; - } - else if ((magic.magic[0] == 'I') && (magic.magic[1] == 'C')) { - // IC – OS/2 struct Icon - got_magic = 1; - } - else if ((magic.magic[0] == 'P') && (magic.magic[1] == 'T')) { - // PT – OS/2 Pointer - got_magic = 1; - } - - if (!got_magic) { - fprintf(stderr, "%s is not a valid BMP file\n", filename); - return -1; - } - - // read BMP header - if ((rval = read(fd, &bmp_hdr, sizeof(bmp_hdr))) < sizeof(bmp_hdr)) { - fprintf(stderr, "error BMP header from file %s\n", filename); - return -1; - } - - // read DIB header - if ((rval = read(fd, &dib_hdr, sizeof(dib_hdr))) < sizeof(dib_hdr)) { - fprintf(stderr, "error reading DIB header from file %s\n", filename); - return -1; - } - -#if 0 - printf("header size: %d\n", dib_hdr.hdr_size); - printf("width: %d\n", dib_hdr.width); - printf("height: %d\n", dib_hdr.height); - printf("num planes: %d\n", dib_hdr.nplanes); - printf("bpp: %d\n", dib_hdr.bpp); - printf("comp type: %d\n", dib_hdr.compress_type); - printf("image size: %d\n", dib_hdr.image_size); - printf("hres: %d\n", dib_hdr.hres); - printf("vres: %d\n", dib_hdr.vres); - printf("ncolors: %d\n", dib_hdr.ncolors); - printf("nimpcolors: %d\n", dib_hdr.nimpcolors); -#endif - - if (dib_hdr.compress_type) { - printf("TODO: compressed images not yet supported\n"); - return -1; - } - - pic_info->width = dib_hdr.width; - pic_info->height = dib_hdr.height; - - if (dib_hdr.bpp == 24) { - rval = parse_bmp_24(&bmp_hdr, &dib_hdr, fd, pic_info); - } - close(fd); - return rval; -} - -/** - * extract 24bit BMP data from image file - * - * @return 0 on success - * @return -1 on failure - */ - -int parse_bmp_24( - struct bmp_hdr *bmp_hdr, - struct dib_hdr *dib_hdr, - int fd, - struct pic_info *pic_info -) -{ - char *file_data; - char *ptr_file_data; - char *mem_data; - char *ptr_mem_data; - char *cptr; - - int w = dib_hdr->width; // picture width - int h = dib_hdr->height; // picture height - int bpl; // bytes per line - int bytes; - int i; - int j; - - // bytes per image line = width x bytes_per_pixel + padding - i = (w * 3) % 4; - j = (i == 0) ? 0 : 4 - i; - bpl = w * 3 + j; - - // 24 bit depth, no alpha channel - file_data = (char *) malloc(h * bpl); - - // point to first line in image data, which is stored in reverse order - ptr_file_data = (file_data + dib_hdr->image_size) - bpl; - - // 24 bit depth, with alpha channel - mem_data = (char *) malloc(w * h * 4); - ptr_mem_data = mem_data; - - pic_info->pixel_data = ptr_mem_data; - - // seek to beginning of pixel data - lseek(fd, bmp_hdr->offset, SEEK_SET); - - // read all pixel data - bytes = read(fd, file_data, dib_hdr->image_size); - - // convert 24bit to 24 bit with alpha and store in reverse - for (i = 0; i < h; i ++) - { - cptr = ptr_file_data; - for (j = 0; j < w; j++) - { - *ptr_mem_data++ = *cptr++; // blue value - *ptr_mem_data++ = *cptr++; // green value - *ptr_mem_data++ = *cptr++; // red value - *ptr_mem_data++ = 0; // alpha channel - } - ptr_file_data -= bpl; - } - - free(file_data); - return 0; -} diff --git a/tests/xdemo/commit.txt b/tests/xdemo/commit.txt deleted file mode 100644 index 4ad4fffe..00000000 --- a/tests/xdemo/commit.txt +++ /dev/null @@ -1 +0,0 @@ -First commit for the project Ver 1.0 diff --git a/tests/xdemo/common.h b/tests/xdemo/common.h deleted file mode 100644 index 2ce75bba..00000000 --- a/tests/xdemo/common.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __XDEMO_H -#define __XDEMO_H - -#define DEBUG - -#ifdef DEBUG -#define dprint(x...) printf(x) -#else -#define dprint(x...) -#endif - -struct pic_info -{ - int width; - int height; - char *pixel_data; -}; - -#endif diff --git a/tests/xdemo/xdemo.c b/tests/xdemo/xdemo.c deleted file mode 100644 index 073516f0..00000000 --- a/tests/xdemo/xdemo.c +++ /dev/null @@ -1,674 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -// LK_TODO -// http://tronche.com/gui/x/xlib/GC/convenience-functions/fill-tile-and-stipple.html -// fill stipple - -// drawfonts: XDrawString, XDrawImageString XDrawText XLoadFont XTextExtents -// http://www.ac3.edu.au/SGI_Developer/books/XLib_PG/sgi_html/apa.html -// http://www.ac3.edu.au/SGI_Developer/books/XLib_PG/sgi_html/index.html - -// use jpg lib to convert bmp to jpg and vice versa - -#define MAX_COLORS 5 -#define SCROLL_JUMP 1 // scroll in increments of g_winHeight -#define SCROLL_SMOOTH1 2 // scroll using XPutImage + XCopyArea -#define SCROLL_SMOOTH2 3 // scroll using XPutImage only - -int parse_bmp(char *filename, struct pic_info *); -int drawBMP(char *filename, int scroll_type); -int signal_tcp_proxy(char *proxy_app); - -// globals -Display *g_disp; -Window g_win; -XColor g_colors[MAX_COLORS]; -GC g_gc; -int g_winWidth; -int g_winHeight; -int g_delay_dur; - -void start_timer(struct timeval *tv) -{ - gettimeofday(tv, NULL); -} - - -uint32_t time_elapsed_ms(struct timeval tv) -{ - struct timeval tv_now; - uint32_t dur; - - gettimeofday(&tv_now, NULL); - dur = ((tv_now.tv_sec - tv.tv_sec) * 1000) + ((tv_now.tv_usec - tv.tv_usec) / 1000); - return dur; -} - - -uint32_t time_elapsed_us(struct timeval tv) -{ - struct timeval tv_now; - uint32_t dur; - - gettimeofday(&tv_now, NULL); - dur = ((tv_now.tv_sec - tv.tv_sec) * 1000000) + (tv_now.tv_usec - tv.tv_usec); - return dur; -} - -int drawLines(int count) -{ - int x1; - int y1; - int x2; - int y2; - int i; - int index; - - if (count <= 0) { - return 0; // nothing to do - } - - srandom(time(NULL)); - XClearArea(g_disp, g_win, 0, 0, g_winWidth, g_winHeight, 0); - - for (i = 0, index = 0; i < count; i++) - { - x1 = random() % g_winWidth; - y1 = random() % g_winHeight; - x2 = random() % g_winWidth; - y2 = random() % g_winHeight; - XSetForeground(g_disp, g_gc, g_colors[index++].pixel); - if (index == MAX_COLORS) { - index = 0; - } - // from-to - XDrawLine(g_disp, g_win, g_gc, x1, y1, x2, y2); - XFlush(g_disp); - usleep(g_delay_dur); - } - return 0; -} - -// LK_TODO support user defined w and h - -int drawRectangles(int count) -{ - int x1; - int y1; - int w; - int h; - int i; - int index; - - if (count <= 0) { - return 0; // nothing to do - } - - srandom(time(NULL)); - XClearArea(g_disp, g_win, 0, 0, g_winWidth, g_winHeight, 0); - - for (i = 0, index = 0; i < count; i++) - { - x1 = random() % g_winWidth; - y1 = random() % g_winHeight; - w = 160; - h = 140; - XSetForeground(g_disp, g_gc, g_colors[index++].pixel); - if (index == MAX_COLORS) { - index = 0; - } - //XDrawRectangle(g_disp, g_win, g_gc, x1, y1, w, h); - XFillRectangle(g_disp, g_win, g_gc, x1, y1, w, h); - XFlush(g_disp); - usleep(g_delay_dur); - } - return 0; -} - -int drawFont(int count, char *msg) -{ - int x1; - int y1; - int i; - int index; - -#ifdef CHANGE_FONT_SIZE - int w; - int h; - int actual_count; - char **font_list; -#endif - - if (count <= 0) { - return 0; // nothing to do - } - - srandom(time(NULL)); - XClearArea(g_disp, g_win, 0, 0, g_winWidth, g_winHeight, 0); - -#ifdef CHANGE_FONT_SIZE - font_list = XListFonts(g_disp, "−*−courier−*−*−*−*−0−0−*−*−*−0−*−*", 2000, &actual_count); - if (!font_list) { - printf("actual_count=%d\n", actual_count); - for (i = 0; i < actual_count; i++) - { - printf("%s\n", font_list[i]); - } - XFreeFontNames(font_list); - } - else { - printf("XListFonts() reted NULL\n"); - } -#endif - - srandom(time(NULL)); - - for (i = 0, index = 0; i < count; i++) - { - x1 = random() % g_winWidth; - y1 = random() % g_winHeight; - XSetForeground(g_disp, g_gc, g_colors[index++].pixel); - if (index == MAX_COLORS) { - index = 0; - } - XDrawString(g_disp, g_win, g_gc, x1, y1, msg, strlen(msg)); - XFlush(g_disp); - usleep(g_delay_dur); - } - return 0; // nothing to do -} - -/** - * display a usage message - */ - -void -usage() -{ - printf("usage: xdemo [-l] [-r] [-s] [-f ] [-i ] [-g ] [-c ] [-o ] [-d ] -z\n"); - printf(" -l draw lines\n"); - printf(" -r draw fill rectangles\n"); - printf(" -s draw stipple rectangles\n"); - printf(" -f draw string using fonts\n"); - printf(" -i draw image\n"); - printf(" -g geometry, default is 640x480\n"); - printf(" -c iteration count, default is 5000\n"); - printf(" -d loop delay in micro seconds, default 1000\n"); - printf(" -o define scrolling method\n"); - printf(" -z zero proxy counters for specified application\n\n"); -} - -int main(int argc, char **argv) -{ - XEvent evt; - Colormap colormap; - struct timeval tv; - int screenNumber; - long eventMask; - unsigned long white; - unsigned long black; - Status rc; - int iters; - int opt; - int draw_lines; - int draw_rects; - int draw_stipples; - int draw_fonts; - int draw_image; - int zero_counters; - int scroll_type; - char image_file[256]; - char proxy_app[256]; - char msg[4096]; - - // set some defaults - g_winWidth = 640; - g_winHeight = 480; - iters = 5000; - draw_lines = 1; - draw_rects = 1; - draw_stipples = 1; - draw_fonts = 1; - draw_image = 1; - g_delay_dur = 1000; - scroll_type = SCROLL_SMOOTH1; - zero_counters = 0; - strcpy(image_file, "yosemite.bmp"); - strcpy(msg, "To be or not to be!"); - - // process cmd line args - opterr = 0; - while ((opt = getopt(argc, argv, "lrsg:c:f:i:d:o:z:")) != -1) - { - switch (opt) - { - case 'g': - if (sscanf(optarg, "%dx%d", &g_winWidth, &g_winHeight) != 2) { - fprintf(stderr, "\nerror: invalid geometry specified\n\n"); - usage(); - return -1; - } - break; - - case 'c': - if (sscanf(optarg, "%d", &iters) != 1) { - fprintf(stderr, "\nerror: invalid count specified\n\n"); - usage(); - return -1; - } - break; - - case 'l': - draw_lines = 1; - draw_rects = 0; - draw_stipples = 0; - draw_fonts = 0; - draw_image = 0; - break; - - case 'r': - draw_rects = 1; - draw_lines = 0; - draw_stipples = 0; - draw_fonts = 0; - draw_image = 0; - break; - - case 's': - draw_stipples = 1; - draw_lines = 0; - draw_rects = 0; - draw_fonts = 0; - draw_image = 0; - break; - - case 'f': - if (strlen(optarg) <= 0) { - fprintf(stderr, "\nerror: -f option requires an argument\n\n"); - usage(); - return -1; - } - draw_fonts = 1; - strncpy(msg, optarg, 4096); - draw_lines = 0; - draw_rects = 0; - draw_stipples = 0; - draw_image = 0; - break; - - case 'i': - if (strlen(optarg) <= 0) { - fprintf(stderr, "\nerror: -i option requires an argument\n\n"); - usage(); - return -1; - } - draw_image = 1; - strncpy(image_file, optarg, 255); - draw_lines = 0; - draw_rects = 0; - draw_stipples = 0; - draw_fonts = 0; - break; - - case 'h': - usage(); - return 0; - break; - - case 'v': - printf("xdemo Ver 1.0\n"); - return 0; - break; - - case 'd': - if (sscanf(optarg, "%d", &g_delay_dur) != 1) { - fprintf(stderr, "\nerror: -d option requires an argument\n\n"); - usage(); - return -1; - } - break; - - case 'z': - if (strlen(optarg) <= 0) { - fprintf(stderr, "\nerror: invalid proxy application specified\n\n"); - usage(); - return -1; - } - strcpy(proxy_app, optarg); - printf("##### LK_TODO: proxy_app=%s\n", proxy_app); - zero_counters = 1; - break; - - case 'o': - if (strcmp(optarg, "jump") == 0) { - scroll_type = SCROLL_JUMP; - } - else if (strcmp(optarg, "smooth1") == 0) { - scroll_type = SCROLL_SMOOTH1; - } - else if (strcmp(optarg, "smooth2") == 0) { - scroll_type = SCROLL_SMOOTH2; - } - else { - fprintf(stderr, "\ninvalid scroll type specified\n\n"); - usage(); - return -1; - } - break; - - default: - usage(); - return -1; - } - } - - // must have at least one operation - if ((!draw_lines) && (!draw_rects) && (!draw_stipples) && - (!draw_fonts) && (!draw_image)) { - usage(); - return -1; - } - - g_disp = XOpenDisplay(NULL); - if (!g_disp) { - dprint("error opening X display\n"); - exit(-1); - } - - screenNumber = DefaultScreen(g_disp); - white = WhitePixel(g_disp, screenNumber); - black = BlackPixel(g_disp, screenNumber); - - g_win = XCreateSimpleWindow(g_disp, - DefaultRootWindow(g_disp), - 50, 50, // origin - g_winWidth, g_winHeight, // size - 0, black, // border - white ); // backgd - - XMapWindow(g_disp, g_win); - //eventMask = StructureNotifyMask | MapNotify | VisibilityChangeMask; - eventMask = StructureNotifyMask | VisibilityChangeMask; - XSelectInput(g_disp, g_win, eventMask); - - g_gc = XCreateGC(g_disp, g_win, - 0, // mask of values - NULL ); // array of values - #if 0 - do - { - dprint("about to call XNextEvent(...)\n"); - XNextEvent(g_disp, &evt);// calls XFlush - dprint("returned from XNextEvent(...)\n"); - } - //while(evt.type != MapNotify); - while(evt.type != VisibilityNotify); - #endif - - // get access to the screen's color map - colormap = DefaultColormap(g_disp, screenNumber); - - // alloc red color - rc = XAllocNamedColor(g_disp, colormap, "red", &g_colors[0], &g_colors[0]); - if (rc == 0) { - printf("XAllocNamedColor - failed to allocated 'red' color.\n"); - exit(1); - } - - rc = XAllocNamedColor(g_disp, colormap, "green", &g_colors[1], &g_colors[1]); - if (rc == 0) { - printf("XAllocNamedColor - failed to allocated 'green' color.\n"); - exit(1); - } - - rc = XAllocNamedColor(g_disp, colormap, "blue", &g_colors[2], &g_colors[2]); - if (rc == 0) { - printf("XAllocNamedColor - failed to allocated 'blue' color.\n"); - exit(1); - } - rc = XAllocNamedColor(g_disp, colormap, "yellow", &g_colors[3], &g_colors[3]); - if (rc == 0) { - printf("XAllocNamedColor - failed to allocated 'yellow' color.\n"); - exit(1); - } - rc = XAllocNamedColor(g_disp, colormap, "orange", &g_colors[4], &g_colors[4]); - if (rc == 0) { - printf("XAllocNamedColor - failed to allocated 'orange' color.\n"); - exit(1); - } - - if (zero_counters) { - signal_tcp_proxy(proxy_app); - } - - if (draw_lines) { - start_timer(&tv); - drawLines(iters); - printf("drew %d lines in %d ms\n", iters, time_elapsed_ms(tv)); - } - - if (draw_rects) { - start_timer(&tv); - drawRectangles(iters); - printf("drew %d rects in %d ms\n", iters, time_elapsed_ms(tv)); - } - - if (draw_stipples) { - start_timer(&tv); - // LK_TODO - } - - if (draw_fonts) { - start_timer(&tv); - drawFont(iters, msg); - printf("drew %d strings in %d ms\n", iters, time_elapsed_ms(tv)); - } - - if (draw_image) { - start_timer(&tv); - drawBMP(image_file, scroll_type); - printf("drew BMP in %d ms\n", time_elapsed_ms(tv)); - } - - if (zero_counters) { - signal_tcp_proxy(proxy_app); - } - - eventMask = ButtonPressMask|ButtonReleaseMask; - - XSelectInput(g_disp, g_win, eventMask); - - do - { - XNextEvent(g_disp, &evt); // calls XFlush() - } - while(evt.type != ButtonRelease); - - XDestroyWindow(g_disp, g_win); - XCloseDisplay(g_disp); - - return 0; -} - -int drawBMP(char *filename, int scroll_type) -{ - struct pic_info pic_info; - XImage *image; - Visual *visual; - Pixmap pixmap; - int depth; - int i; - int j; - - if (parse_bmp(filename, &pic_info) < 0) { - exit(-1); - } - XClearArea(g_disp, g_win, 0, 0, g_winWidth, g_winHeight, 0); - - depth = DefaultDepth(g_disp, DefaultScreen(g_disp)); - visual = DefaultVisual(g_disp, DefaultScreen(g_disp)); - - // create empty pixmap - pixmap = XCreatePixmap(g_disp, g_win, pic_info.width, pic_info.height, depth); - - // create an image from pixel data - image = XCreateImage(g_disp, visual, depth, ZPixmap, 0, pic_info.pixel_data, - pic_info.width, pic_info.height, 32, 0); - - if (pic_info.height <= g_winHeight) { - // image is too small to scroll - XFlush(g_disp); - XPutImage(g_disp, g_win, g_gc, image, 0, 0, 0, 0, pic_info.width, pic_info.height); - XFlush(g_disp); - return 0; - } - - if (scroll_type == SCROLL_JUMP) { - // copy image to pixelmap - XPutImage(g_disp, pixmap, g_gc, image, 0, 0, 0, 0, pic_info.width, pic_info.height); - - if (pic_info.height <= g_winHeight) { - // image too small - no scrolling required - XFlush(g_disp); - XCopyArea(g_disp, // connection to X server - pixmap, // source drawable - g_win, // dest drawable - g_gc, // graphics context - 0, 0, // source x,y - pic_info.width, // width - pic_info.height, // height - 0, 0); // dest x,y - XFlush(g_disp); - return 0; - } - - j = pic_info.height / g_winHeight; - if (pic_info.height % g_winHeight != 0) { - // need to include the last part of the image - j++; - } - XFlush(g_disp); - for (i = 0; i < j; i++) - { - XCopyArea(g_disp, // connection to X server - pixmap, // source drawable - g_win, // dest drawable - g_gc, // graphics context - 0, i * g_winHeight, // source x,y - pic_info.width, // width - pic_info.height, // height - 0, 0); // dest x,y - XFlush(g_disp); - sleep(3); - } - } - - /* - ** smooth scroll the image - */ - - // number of lines to be scrolled - j = pic_info.height - g_winHeight; - - if (scroll_type == SCROLL_SMOOTH1) { - XFlush(g_disp); - XPutImage(g_disp, g_win, g_gc, image, 0, 0, 0, 0, pic_info.width, pic_info.height); - XFlush(g_disp); - usleep(10000); - for (i = 0; i < j; i++) - { - XCopyArea(g_disp, g_win, g_win, g_gc, 0, 1, g_winWidth, g_winHeight - 1, 0, 0); - XPutImage(g_disp, g_win, g_gc, image, 0, g_winHeight + i, 0, g_winHeight -1 , pic_info.width, 1); - XFlush(g_disp); - usleep(10000); - } - return 0; - } - - if (scroll_type == SCROLL_SMOOTH2) { - XFlush(g_disp); - for (i = 0; i < j; i++) - { - XPutImage(g_disp, g_win, g_gc, image, 0, i, 0, 0, pic_info.width, pic_info.height - i); - XFlush(g_disp); - usleep(10000); - } - } - return 0; -} - -int process_bmp_event() -{ - XEvent ev; - long event_mask; - - event_mask = ExposureMask|ButtonPressMask|ButtonReleaseMask|StructureNotifyMask; - XSelectInput(g_disp, g_win, event_mask); - XNextEvent(g_disp, &ev); - switch(ev.type) - { - case Expose: - printf("got expose event\n"); - break; - - default: - printf("did not get expose event\n"); - break; - } - return 0; -} - -/** - * send a SIGUSR1 to process tcp_proxy, causing it to clear counters - * - * @return 0 on success, -1 on failure - */ - -int signal_tcp_proxy(char *proc_name) -{ - FILE *fp; - char *cptr; - char buf[2048]; - int pids[10]; - int status = 0; - int num_procs; - int i; - - sprintf(buf, "pidof %s", proc_name); - if ((fp = popen(buf, "r")) == NULL ) { - printf("xdemo: popen() failed\n"); - return -1; - } - - cptr = fgets(buf, 2047, fp); - if (cptr == NULL) { - pclose(fp); - return -1; - } - - num_procs = sscanf(buf, "%d %d %d %d %d %d %d %d %d %d", - &pids[0], &pids[1], &pids[2], &pids[3], &pids[4], - &pids[5], &pids[6], &pids[7], &pids[8], &pids[9]); - if (num_procs > 0) { - for (i = 0; i < num_procs; i++) { - kill(pids[i], SIGUSR1); - printf("sent SIGUSR1 to process %d\n", pids[i]); - } - } - - pclose(fp); - return status; -} - diff --git a/tests/xdemo/yosemite.bmp b/tests/xdemo/yosemite.bmp deleted file mode 100644 index c64aba756c26fe05b64977b4a6982caaca095a79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1843254 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%0DMZm8iI1F|iR!rjOhhrR;X&)LHpF9#)rdrMT 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 $wmPA3#jTOxqa9K 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

PZI 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≫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Ν|#(sJJj7 zW8X)Hgb`wH#odqNCs7StOBIy%nK0R*`7LORSefIBz#wnmy8|^eDmEJC#Q@(i__zon zGM0l6rXYc99Ta{CxZGheL2!hHxoHN*gkqzDQDH%G4?*~hBE$p!f}s{ba0vck`*Kgu z@nqlA<tjS!5L+TChtsFvqt^IeW4k>DOO?k*xG z9EFHUN&wp^9Gk&bN_lFf+HTdkQYCt`RHbxS)NR#yE#=v25mPRex_w}4+W7jg@9XR7 z-@YtAe?Iv4|2X{Te_wz3`{8$gUOxZn`0Eq$5@v`a5>5i@LuASbY?ZJV~{_3%s z!GqDEikp;Kl22r5RC=Sgp?NHT~N zUUT=(Z1cf<>S$BJ&P4s?T3~t5KhX{;x)~jfh-6CB+(hNttf99_1nKh?z)K%Y>u=AR z8G>-Gu@6tj-dv79KZE25l0qU(cYsH0?%as5G8e4jV7|qB?;m~vPU4; zTLH?*!qDPj&HEOlAMQ!NcEeL3Zs z96pgijzf`r2ApJ8IAX`ls-({f=M`ba!$sK<5dfPKCL(!8~pL4{PkMihb@S`v%FokzF#-ITvT6A zsjeo$@L2|e)5}TO^9lL0amnKm#gj43^GW6Ph~i?<^kUlfde!lMGyThv>CLL|w{y?0 zXSOc~?%&VlKOJd*JA?Yy1Q-AHJo7(Z`2O)E>z~j4KRqh@>5AP~4g+6tTOovKR6Jd! zH)k^gsbP9H!XW`ZGcjO~Op^y&1=s?suB8xc!5|rjp%h^_v=}CVVv|Fii&QdE8V=Q= zgp+s`3+QLirpB2>`~ru*IWKR$AM8m%Bwq3PDEqq&*Xt$w)tKpYz;Qk9dOD@q?=qhB z+b&0$Gv)HDegM$G*G=F1c_>;N|2V3-9Fyd$nN7~T@0NXk9vFYylE0rZy`M{YHz&Iu zEW8-WIT@&Ux14@CVmt0}oc5(X8nWzl+(_PzdjQa7TTRZ>e)nNd%5J-Erxj9ccTdr4awZd>j zzS+WuV5Y;K8{d+n0nMXP)#(uAG=V@H#v;k9jqIHc$h-h!ZSrsc-gSnf(Ryo?J$6o^-NKKHXqiYS&IR$cL&Wy=AQCTyak+x4%RQgm%$;tfzc5Ff~az=F8g52e=wSVIO1ArO_^>$c@?^5zv_S7>WUuC zm7GrdL7KEN263EsVuE0U9TfBM9yD*En1gJB@CQ)@q-V4dRBw)zw$%A1_i~$Kq0zcl zRsM9e>TL-(O$6oQQk|ijGGR(eOIH3BCJm=v}CVAI62>3;7mq zQ*g7o6ZS0>>9@lF7Dh~B zJu>2UQe+4PZo6@KDVOOnD{6AhJ=NCsYGIa#X*T0*26ko|#bzYvRRo0uL8rt~NoYD1 zJ_P8F3iV2pqc5`|o%gb#}$mgWTV`}><`Mq4@?3q1~XXistuZB*} zJJ${%OulLHsBLn)sb!{SaHo6vVtn@TT-AJi$!u-*a7o2VtGU2bHe7l5<$U?g_RQ0j zsTXUFy929V&pKXgR-8`fZ4cXLnrp9?%l4;WT$?r7YADYDJto~MO{>i}mH5C0L0^`o zEX{!63AsO2R_F$Q<5;IA-XINy$ibLMFf@avE`d$M^BAEd6x}G7W>};6qzF9X9_-~* ztUD5Ne3}Y~)~!d2rkdP}zD{Gh>tS4sCe4vjUI-SZ>`WIo)77vroj=r*KREzN_d_qv zTJ~46dz#E;ex=Wi(a2)-a?4;FIK|n9TE%5K5D1$))(yUAC?1_6WWxp~6v8&SG^Rx@ z%XGjZ>cmtNyb?R?2Vkp~DCa&5n^X5CW_uL#HXUBSg4x z4hp3Jg$v2uT97r;oIcuY>8|AD+Qaz-oQ@CVG+t!}D<9}yrC@`TfDx-7bgH3>2(*MRF7c8G;TALI#H*g3#oIL<%Yb85$D(0Jep&Aq4h*oSY%ew((us zLQnqvk?43nh&xB4~BxiyEg-OqNwbQH+jVEI_OJyNnWTCy?NdNAF!H4cBR zWT?$?2rQ4#G~W*k!^YvTG1T}7nNL5mI7lQQ2uV>mavVcKr3*=k_-HDhaMOQgB_Z*M zxTI(X4a*YHq;5mY`;)qtd(|&@t6uNdeK@WDcvk#&zu@I|{oBK)?@r)){j2?o#~VO^ zuY0~zdA;8Jc(v|m+R|D8JgY<6;}W&NF1X1$M*>FbR` zV7HTwni-jr7yG-1Ehp?J z!-~_gAMldG7oQ@A*INT>YOPdta<~yj-uo znyY`Y+Wcm-@Mx4;Zp%CvD0;VMyBza8n+581;PGtX^M$OZv+gfDhG$c%^C8od$+Y(? zY2U3HU(Om{&FQblEzf6+PbMJ>+4*__7)_qHi>_C58J7c|i$18qQx4k<`z@xEj@0V` z=hK_=*>gVVyB^Cp8#GOqgMbb!Wh5)LHwnwrC4#|ROo8$naV$AQOiJSsU0htYoL*#L zlv&vIE^ez=K2oHct+uYUSl7Ct{LI=KEIFF0f3yIr`g8`$4Ul7}AB<#Q&ZnJB+mELq z!5RE2!B83`$?Cl^&^V_Yj(g6hedkk|CljFl&R^;h=35lG7BT1xm%Gaj#tSz3;bLHa zHc2l8(1A!GpmPL=1wDLlKLO-E_wRuhN9Xxs#nqhuXfW?!AaFEPcraA+V#>eSYVR$` z9jXbz-{28|H8vr>{K;73hqbb+DS-H(q{s-wjiWLcMFI|j#hkN1X5|>03PzhX8JRKbt8v+iNXdDuD_)z>pT?texcq%Z~00@RT@9mH~ zw}SrmZDbI*-~x~(P_PIX%#ji!P|;BT-VMD6jcA}c!_Ni-2!qlWm{D;LgQD-lDEUER z7&M>|JOVTuqmt0!NJMZ<7(>KTSk-sKgYJWBI4&YOA^KkAeW-u&S{}6ZLgK@Mk)ihy z!FQtWL$wPh(YRO=pNgg=0{Fs<2P+0F85@a+0A~+?VDKlQh^WxO52nXqjBIMUl9jDD zHDyWi?3o>va*r9yxiJJwA`u~Rk0%l{*c_EXFE%KYP95JYL$h#+Ogzwj=p;NcDITL_ zfm0j^2P}QH%F05NR*p8RXwDQ0c>S4m5W*OYg#c)fQ&ONO0HvA4s&@pkQwnlKE-TBd zkL5DC25nVWb7gyVdSP05Q<2;6vZklnGrUTtD!-|qZLY0jwYzVBq;9FJb8iZYg(MA* z;b18X_0z9bN1iPg&NcdH>q|F!WcfySPoVpHq2pp^^@rp9(dwf4mbo8KCw{)_`)~qZ zPVn|`dbU-0IMZ>tQMNqfX(@(sBRNIptjK{*FG(-5)fQ+75qgyUi&Xs8G--ricGuFla^=k%Pd3bIn7 z5~4v(7LAEbWRW0GBrx2;Of$lg`Ms<(Gu>%a6=ju7_2u?8%d_mR>il>IXc=teN$GS<42_h4V_-BMgVt>z&=Zph z@l14dA{*my>yydxAUFa~c%4pQP;spaj#$N(@kp@HBqW%~F_Q6szf6OOSLERrr%S4H zL^XbGR|ROj`Ar27#i*&vmse&>OMQ@-3=3#=riK67lod}mm9BKv9ZwYP4!Y)>y54R# zUN5vgTY+AE^NWqT$IE5Mlf?&PFh2@x55Zl!^X-2B_s3mt_G-`PTdr5TpKmpvFSK1Q z_dVTizg(+5n(KVA+wf$g;FPkg;Q}@+6yr45rzsYMfmOo+OE8A=sF}*htlyZyl@A4_89dqv~I; zGd>==-fa0k99UosdNyT$u?F@RhOJIky@!#bg>H$kB@^7YD#3&##|Xx570Z2!-V)t( zqj!7II@Opm)#%>nd--2qMz7bK4yO8^ZZ7@yeCEql!^v!@mJZ6GntwbF{QWBb_lvaW zi)oiLz{K{vUUk1&12<`K&vrhY&--$e_4O$2$9?O^t+GF_Ja5-;9`ItJ?C0a0cdIpj zoR|K%SNDFi;^lJ2(NO7|RsYjj@6}}B`;Gi}t7WfOD&DTaf33TmN$Je1I~i~PxL5gk zui}TD>bL7*{kpTUUBARR9h@M`OMn-~tU`6zsUjU|d)TCORCA zh)N6zP7V#jJPe7!BAQNaI`9S0Ci5(d|tqHX@9zlmns#;gPB=XR?4EeE${#6XUJUi(w?9&`2Vc0Fk>P zkq;py0a(q6j3g8d6BQc_sv;zqJ)$FFpMN*_Z?FJH5r}Y*@dCpNVvL{{9TI)>Q@8Hj z3W*JaYBvFoia{gphd+1_{s8D$QSspT{16@wMwFo;w}V5zg<=8xte}{RU}F9j7lOiL zqa(lrDnAsZw*Yo z-0Htx0!nlD)iUs}^0o%b9?hw{165l?Wec69tG&Y?ju-!Yx%6*u0D@az?zTSJ%%1Je zo$Sz7WoNWkKvOieJiDl?j$xE&^WA`A&~%OB;t{MQw165bpuo)m3QQo>VUY*~1{IkY z7lTJf;ZZPY4aOsbiE*&vnYddKcS1gu?e7Qf=+ee zc!#7Y9V}Iuc`k~_#P>TK4Mk<+9bKDKmWpgufs>zVG?(Twy(x@5m$;?KvpH%72h@#0 zQExe;JUv>?iezCExC9tFz+5b~y{v9!!rfji$WBG;L|__>HA;at28+U@<9QSmp8^#< zwC@lyIz;@y-H)tFj%K1*cB!c!BuB-`o1z*vmb~+2or}QAVab?0viP= z9D;Zd5&saJU~lYbC<*X+#tO;MVgi0ILWoZg;G?LqC^kAiIbM~j(0jD1G!;KZR6bOv zE424MTAF>eS2WgOukvxy6hxa4@0Qv7%g;aW4QzBw?hg$tcNNrUZJ)22(zHo5G>-;y zD=LLUz;g*S37y2kiG_4F3B@F$h=h17EfEV|jvNAkhM^J?xL^#z!6LB{bV@uC6A6JV zWHJ&WBYZmX;}^#{ZX=u%85kTZiN&MPxMU2EBxjJ6Op2BdL8cU)jBikhSqy?$$fWaW zkjnNA|adjF!%H%{q-%NAS=0NGraMj*e z)7f0@{&>*}w9xxNj+fe74Le3bq08M{Q?WGYY%LY%r8=u~b%kz4ZfgE;v!$^xtryrY zwc3^<*FcS}yF7QcvwUMDd!{32wli;`$2nLFP9W(k{RMkdr3ceh`w&1jCo4)#PE*3p zL7ZiQErif(AnW-|i-f3V6ICoIb>SD~cGc4%9$L&os(47dOxTobsVk7=yVyQ+q=Xiy zVkem;5L&^@vQko2U`GiaV&G(AXaVn(GG2wtHBqnK7)-lZgoG^VLMO~vQ%~ozpKsZY zrt9{`4EZ)h;zKkw*45x|+#T!R9`_bHGjd#&y$$k!8wMiHTT`Hg2a!8?{Y^dE8aP~P z-I)RFyz#fEjfeBF60Oqu*L&cVQSwcgbAe#h1jhvjLvOW5=1D$?6d=ZAiI-0;Wa*54o3zuT)inaLWg2_Z$hirmr^NpM0? zk|>^Gq_EQk(rT-$C)2Up=6yDv_i+V=1*xysU^9^WW+U&-s^`gc=G$f8`_;nl*0SC# z=YHPx|8yMq^NI8QzV-PQsFnopb~Rs5MXxsuANQS~k5a$ea=u-2yju3Z+f44xkIGVE z%I)AA2HOniCm0`1=DymAwaXuZV^wS@7(+cofx;mq4*JAV5%*DH`J27P?-%plO*;=- z3m%W;o(;MCD?-@uV0gt7Q=_8pMIuAKjl3;&>2fdnEwdG>w#-`z_YkNE2rm5F{d;7& z6m%1}V#A^t1gKuIvEbSqBC%^QJThQVNL2X4=!n~)_kndIF{|lv-fdtJ$KD57F}Qia zCK>Ske)t_2zlKHKht4ptnjv8j^t|9d0N4r@E_hfyhzJ60FNTCcVv%qKd^Vs)28<4Z z>tPQ-qZAJw8{zjME#e{aVF)@rm>7F2{9agCSR4qLzPT3;)7_YmBsLBmkAOG^kPL^1 z2SErRxM(J^@QG|Z{0ewlSn!-+eE>&Di6YSmVF+;ILO|0V@b@oPYIJN&M06xRJ~j!3 zL?WZ$VQ69k4D9}=kiT;e6~)m=xpE;_zyq%*h+U4xV&f=eickRUVwJ~AQS-49`pqXp z#3V7Oczi698b`8=fS3w)b2(6+LLch|VMKtTN23@>HMKjB2PCeOY#rf>k!M5bWbZ)K-BHPd^0nA~=*>=9q0u2!O zXQEO<&}qeKGE2ZF^{Er&WJ|Sg@!fIn#q#6-{k8GMX4%tK*asG#&%!;bZfC4`rOz|h zR((2Kf3;k5zEt;UrFeVHIZy|GfM7A9^g9fNZeM*slW7;Z^jg20XplmJ9w0?58yC;O zfTt*gu*=*Q7}gUKk$46bfkQ>(P+^!j@U9HT#s=XK;WTt8Ar58%@ZfM#Jmk4x)Lg1l z69d7=(8NyDg|jhKmnx;Lm{*bp{y+AS`t-&Ao21?TI%U9(Rx$Gj>a%();g%(JTe910 zvU=*2)qVinw9R45?x=o$q~OJ7+FHN7HX8+AXIUxwBDbm5?;WZK;{u#n4htb?Q&Yhj zH#Jtlp*Xa39u?0aA(%LbwdJH6k_>`4G5H=Lnkb_Jn_A#j*RKuQI*VDQPSi6p~wlPZM)8)qIzfrlH5m@RAany{}kYY?Y)dE82^+E;(Dr%o(X(c)Pdq zY!kp5@_8vNER#nd(NQcu5lG9h;GfA{JRIrlB)E>JAd^V3aPIP&Y%VPsyq(E$SRw*W zU||R`L|Ou{t>7`>IZ0z-oxT*6QIgCjlNd>`C``yoqp$@GKw&zM!WJis)V!NuYc-oK zrBS#z9>6_NrbXnmLRa6~NYPNet1Vz_Ed*?ZNAT6DyzpEykOGURxqPg}V~tHRpp@ zBy`nqHUW5vaD6(^QURR|1{Ne8KT*dcSS0YZOq8>L%LnWQqLkw;&rdJQ%&9Mg?S~}O z?CB^2$#bNRMa?n8?hYJFXqh^aN67@vMzOPKw6SincYI~cmT6@wSR@fuY?TMv$|2+1 zS(+ghGYF*kBz$Z#3(pnOm|T)b$?^J~83i6&x>=j5apk9#v{!g5bFv!(gBk}C75)qbNSQ=`kb1Uib`B`%Jd4zcM8$k2=|2S^J`TFc=#7WC8< zkG5ph`0_gnGg|za^_kTjMHa6*zb(IFy0N&aB)!m6+EfDiMELHRY&wyY15^qOHas35 zCbbItwuYNG`kHqJf#1@w(|`8M%dh|U&&NMMp4}b2e6@S|bgQB=+u=~JT?~Kt_b08> zb+#f~W@BLbY^QZ$#!?apbe89|6m7mf0`HxHMtwq zuSu`SHoL7!3*YIFi(B6bA01Z&T!z+O+@Ko@#z&DG;#NyeM zNF?HB{}35|L)=9{a1^jnBW_|4;}DROn1D@$w+5P#Br*;@B6vLzxNOQyQ@I^U0ydaV zK*TLTa1x$C;qb+JJy)kDE5t-OKaPnbi0QGEgd|}ya3^9#3{`Pv!BlVlOh0%kTHC8+ zId*Q2m7HM~2HYgQBsei9l8gxA`Ljq)d9eC zx>3Q>%cVAh%&J$UnlXF^S;L3azc4~V6bT(q!6Atl1U5c4F#$~>#^TWc!Eq!kD1AaP zh6@h`3qC5xe2)Gcz&|l}7Y>P7R(uW(JU-n_t<-C{%J6~u5 z^NO76s_fLx3cg*HB&Ok|3?Kw1$&zszF5KB7#1shri%G`AAefn^hbkM=WQeKCAU>X{ z;&62Wwn3Ou>MNe^OrLI(^_DT(@(tU=j)MvN=8$2!RX5oTNp`x$F41J8sx4rdXi9F( zk+u~IOWoGS0*IA|BwwH{g;HbgG7#X`B+N^R7m*_fF$jDNk{%z8kGUOnCkWa&s7Mk- zXqk1O*aEpdpe^0XgIr^X^NZxhD|3y4G?_8mkXq>>Sh=7MOCPG>WorfL3Y?sXRa2rh zWL}va%&(XZA^1>%6*F7INCMZWuA;KuazTJ*04s0!c< z5DeG~I4f2#1yVX17xfp^{sp^m{bu;f!NCu5pf=~?dD3J6Uota^NXPyK!DI%Wl1yL< z={y-*sN{(?e1Kp8U--U}IY~g)f~N&3z22kinCk(D?Y_O~Y!Kqr`_+L|Sn>ipv>ME{ zS(du&I28@>SLD;j2ykdM18?L)@tfIG0pD$uE?HHasw;Jw%ROb#0mx0k$;dQyvb#1X zz1Gh%36c#wo?RyK>6Ha`fHO~>KfAreUY*skJ)YTD30@rF4PH3cVXx0r=9@D*3hUS>jUmWkGI$d;43l-q2XZk>NCo`<`fZ~lgJR`_!>G}O)q7%spSVEj!&F4xObS^Qgz~jqz1O8gm&9-bi+~HI5oLTjS z=~aGdn$+K#SJ+bu&}j_VG+9QqM+2XaJw3%+mJR;KdVi|csrUKQ6b7kCC*r91ECrV? zqAShvg6e|NjmeDKeApNZG|BKqmD|NE@KoVr_-ckoL1S|<3>ed)BXv5FC)?q#%5|0a zWa$Q0ij*fOCo4#F1V97{6JGVV1*GmT4&ULP9#2<)SroQKrUH?kpN8?>(E&?JpI$q!OD5qT*uEArZ*?A|7kq{GuLV~XaU@iz zP>EeSwnfIW$lwE)Wm$p04J4~51%s`VM$)h_QwCE_MTw7}pDHeN-J&6Hnwb(RS;>+B zsZ2_JAjAWjL(e(q$(r|UKJ$FRFxSEFEw`=qm%P}Pj5jc#ByTHZ)@F(t{K;9Sw3cFZ znHNeDwoM!_A#i*edsCh$$Bb9ANiqge2)@Y)C^|Zp1TFg5u=sEk8N(8C{(q+4^SRLj zP4d)?TDDY{4kQfWz4zXG4+4ZE2+(_9WU-2@VtGkbDyih9R$Fz)bWe28?%eF$&du&z z+-%%^x`?|^_Yd6<#f^=Pcmn}~APKrR-^?d7pGm1upRsyp!*E-B#hY8J#QK?A7QqeE zcz&f+-fK?Aw2p;z=1xylVMCDJ+m0p|a{i@U;HZ^48yKrzXU^eC+f>f!F^j+yHv-2} z{iMyOwRv^9dLoc=UE-ZfG@0;cY(7!0?5LA0c9S9{PGCk3mn6m{Sm7# zYypUoopn|P=W3lr3I2k@N}W`poi=-oo*1;(>5ACBahE-0!l{L2i)Be%1DroU`TBRS zA(er0DB4UG7AwX5xj;X!$-6O9`UeGU_BgL3DeKnDQwl#pVP7w6DEp@(hQdJ)O6%w* z?VUvR&ceduo!CM_>{aR$7H!N#FJ*P76Po2u)EQ}|5`$vxu%F&;9lW~NzO$TOt9R~i zRE`&xKD&dPi^Jbf-}}|mm5=wfULGBPb$0R7(;xrSuX=X|!;^VCU+5OI?TkC^^5r~* zxm>ZA&lY`FkKEvq*|!!`~1^}3bt-&Dfp_o~6)M9dN^M`s5!gN?b~ zYP&X9hE0Q*Gn?Jz$9roZ-}cVuT>YGl6$vX9t~cnknYp`UZAQ(FFoBNPVwov0e=2f} z%`xk^UpEynPI`41EhJt85KL4=?o!L#8mV6&?w7h3yN&x>siOf99PSsM{`|$##WriX zntMG*&SOtGvvc`UGnc6*qWO@)rBypr`BrXrr5VTv4JH{7OoEL4cRG`d%c^W8et36# zeyvk!7c#YEvX)5CX0n|^cemf#nFsRbPUhF1Y*SDZo=bXbA@H}pT&veI3mfyLeyujB zSE}jGOfH-72SW~**W&eA-A;Wz6`Uz0=Q?GuwOCEo>QSd#VROm#R1Aq#L?~dMc|#%?VUfK*>8vaixau%^)m-;l ztxAtvKH8R0u(Q}Da*y^SRa^npL>ZTeeNH?EFd z`P&cQQkxZazr`E&vGH(NDexv$gyon+pqP~CWaF~Q>k~IXJzQbnIA}X;m3%{Zx#dle zmxFgr3Q1zH;^;l*u)GXD1TxMY%2i^G#+6QJ!#?=0#I2vQDHI-v zhl+Tq(5bhS;?29e2S2`A`|4R_yN_j561Pvp9m5Gu&_1kYa+pR`5;m15&o>&c&pSUp zV|$?Q?n>s#p8seN+ibC1FL^MC?97F?=b&u(kURJG2KRT?K0Zk-SB+J_w&LzS**y5= z#rdB;TmE<_*o{qD1ykxyLaH7U*@UCI5lh+{>888)R(4*W&pq17?R5i# zOzYv=#b3WV{kt!QW8y!4zWx2G&^1x5O?3CM#Xi&l>vc7Nx&e>s=gs zxoUEo)}Noje}&jlma2@O=%3VQL#}E%(8!0{*BU3*-?itASZ1kHhMQNArP0j`HBj zMpPjienJ|pS$hZhbuW~))$mBnJm%ASD^alWy{RkjDn_VuU|((W+Xt!dF4}+jX60Xh zKlrDgvOhkKes-ce>J5qZy_MkUl5ejoid&tH1T#upK%7yfX)Ary=#Bl0?bgu}tBU!w zwdI*?E9cGlrcJVsFg;4fr5ZWWyihkG@hfx*_0=~|$-4U_|)4o93?FgH_2?s#zPq_}xx2tmnA>H!2NvTPE@L+fG*#UJr zFg|9WkX#rmBVZsYzEpA4quQ)XTkx=X0c$h>4Nfh;IxU|pAXbMKiYrg{!C7V4s0irj zC`d1rD_c!#&NU=ubD7jiW&P9Jos*^GFCSp*0@oh@>Fe41>lmtY$AjWQd;hC@|MdU; z+duq2|Lfe{MQzf=q-No4nUi^Ut5aL7mgbA`nJD6OYolJA&nB`Cn^&Q8OKmZoGh;6G zS=KB!`=(KwFYz}PF=bK?lxH4+2v=IgMz6NCF+acBZLhSKj@SFAo9&aelkc9~{{9IC zo89LJwfpP&+kHG{T!Gl?0bxibjTr;IjI|nK&BT;fB@LPImoiC_MlF(%Sr)b+Hvz#Y zPI8Y{>{JQtat7b*ikf@8UpwDqZxkykiaVY1PRGUkcd-oJ^Up+Qw%YMRn2P}@Z7A(i z7^m4Y+gzx}i;+w=Y_@CccmSL_9CX!Y;r98#7vF!jey|K@=LsNnZxb$B;m@_X-f8bO zGlR^`&TMVBnOiLfXClE$(3P;w&((mx+*}#_t<7YMsbC`P3P)VAWFVCYP|rf&VL1`V zN8NFsWzZ?NS{biT=k#bed_iL&>x&1B9;1Zaur`f25wdq$#r5q$xs{KWBFN_8ug9kX zF1vG?J3C#gdNh%=`cjriEn4oE5Gy)sZKCKxg#f~6B94~xIXucp%I=Svye!<&j%t+G zHPVl`bWD_j;h8{cE?!?N1!G2&ay;uc1T2a&v-eVDbE&?zIP>uSZo8djvDa)n7m3*L z`CIj3rSO_wbR%q(xn$#Xt_G4GsZEjVSK_l&F`C_WO~j#NFE&>)!+pMTfmSWiawRJj zbBHHLl`2uD9LYA58n?_5G3mL8Rg3VSfR8{J+z{|(1`7XG=@cri4lk)wx0+#n((wdzD>jnZY)d6}!3W<)O{Vd^f#!}UCiZ-hRxzduvBv#Dt#lZ}slCj~6bsVO5;ZQ%CLFKfj!PzPtR@dFR=_yx=ab&apc{AF!jhsQCu5jR#(Fb_wO(|tR$QMy`uyqL?>{SS zBdqmXj}8}KJ;AE;`su)wv7$w%&liG+&E)n>g3WYsqb+NX&qjS&hbw9{ z*rY}ZwX8CRu%I3Ydr5vlSndG9fbS)}_hG@{FK~QGka?UZbDzgKGvM9Q zJJbq;R780vFJCvUFv#R)xijiScyvVVzO>hya(R-@Xep$l@|~s#r&3{-ur*jl%FwND zEzNWvY$85iPI#IBqRJMI=IdvxIIr-2H=5R;O?W+Xcl|ZzYU3j?l;D_gIjbsFT{Ow~T=*Icl;>#0OW!?Gd z$q)bK=imOfzrXYS#r6!fES(DzyIUY^)Jtd;&UsJ-|e7yXj5iQ(&TDHR7r~@s1vvqKrlr^6Vxb$ zjAFl@ZZ}emBCkR0GfF*L#2E})&}58T`Mr62H#-(G;1wsyUwQvy;klQ8w=%F!N0OKs4g}lokD?3BywCKnkqz-<+wlL3n%;< ztt1ooRkD#(%!oZt_F7blh;ycqO;I>s zilU`NQ`Sh)?aw;~8}+TtS&Mlpl(y+2nrJW$lq9Y&XTF7X%fnKyxBpc!g;Nl{_J96&JqmkWbSBt>)PQ$c&VU|`Cu zGO4**01!cZ2=5Sxr*0|CY9dHnPVnY%?mR|u<@-aly_B6%q{oJ@hfhTT7yOs`?@h^Y z_lSW;zo0P4%lvnU!V_c6f5G2z(S%4Y=3xHIXFy<=7!;(0Xm6n6*cK(X=~h~d z1 zk6B3W*WyK~@3%KTJy`ktsQ>kG__Q5r20bOGA)ruOrpykBQadJ9-c%bWh0-gFV2TqzN1WYanY^WRJU3mrx%7?DpAE}PJb!C%B)HN_Wp zjk%ig&DTt|6t*!%%0J>Z%0tc(PT+CRhaQc2rLOH}J&V=&Tnz|jVg2SO_ZJ`EVTFBa zwdBY|kAfcqWU znKpxws6|8X+LF^nnK`~U&~31!eLUV(tb9!-y1PYnAN7rG4!|mRwu&J zrQ><&MooFtHQZnJy*#wvU!ipOt+19{3_H**OJ#QV;LEjgb>B#4HrusN_mg+}k?jWU zC8TUkwNCBL#WDF5TygF#i_h?BB@WUmii}eW^+sVNGG1@rPHmr!KGB0M9zTG z9yBtC1wAhj_VNz+%bW07)MgG48IlXgUW(7)Ebrnu+ycj!$O|dvy>f#D6E*mY{3X?j z!C%~o91^|66?27hA$P)M3tKHgqcdiU6obK>j}mpJX*^<&SY$RSn_q;6DM3JEss@o? z&VKh9@=J2Nx%15hc4%8I%>38aNi)WctyDo?C@`2pq4)MTkB@))bcu2g7SOD>xblp2 za)td?V!4nQWMl2PBWvdhq_kdzpe;YZ4%Acd^F& zcj@5HuG5!~#bqs;16*CPT(sUbQr1=K_ZBkeyLorOC=_1xTh$)3((ly8qpor_nJq?VI>mfFjnwQbI4vnto5|^X z*6UZtYJN-3mhNWEF|#FZVOYSQ87^Ng3-S32%|fAdDl`-Hmgp^+5-6`J^&=|HO`lsE zi`y$KTG^^+%N|z1$342JRq1r9tJQe17!F0PbNzC?nNH_?se+dm*<7r_Ta6Ye*v-}y z3?nwJ(4v>+vSEfVSPd~8vVSDvw?$nhE@c%Op+Gcj+L6cva-~G8QyEPal-h(u2Lm{Ck_h~X~{7(f*O4bz0#i4-F67yTLhWfd>K7x0(KtYC6%3_lmvB+-OS zB^^OY9=-O_&G)a5UKyJj&Sc@Fz~ZIsta50;-|OO=n6JP%hOl53Q6K=91OFAY7uyxE z%Pj{FUJB8GDF+Y?1qOdF=_+?1uz)Ej4485swAEO&5;e;auk&Q8{DxR8n}P*Hfr%9H zVmSDwcwu}LfO~lhzW>ko3tlt)WokSwo?--i<;FE27{M9v9G*_VXhm3|qf>vHj~$ z!Ca(KM?V+cYg5EWcwb!hL*gVU7ZYT{G8B!? z%@Zc)v`jl9H%v_H$F+80WiBddqQFB`)!sE(cQJF9JJOEAUsOmQKke(|V0aD~AHZ ze`!;h)XPLBx!9~2v8lD`z+1u_SK&=T+eE-3%LGP)*6VgH_=`FX9TpV=sLGm7hLV9; zx7s_~UwU?L^~HnS{&H$_KDyMxdTp4AXAT#l2mQ{gyRBDumw$MaJzeyyRP7ZXxeZ+JRsTt*rs0$*JP}FjSA<04{h6wq8OomFo3S559T4a<)<5?y%Mqh1u4ieuhc9 z#R*q07__#(yubYU`O2%a&DRgw_qR`f_;};_NpetGzQ75;mfxBIe+x@RPthHy`tys0 z)F8Y5a2E*Pcy{>g53i5Dd%XMg#TWni_YeN`)yAviZ~x`DU;Xp1?*91b`5!*}^}qi7 z;*YQ9PWrg5nD%xyTiH$$@U5?wn;W&>UaL?Kx)TOh+5q_0*7Kf%IZ|`l;|iNa4E}mt zig?tF`Pt`D;l-*|LjCpm#m&Li?#kBo($Vd$R<~BHWmorBj!xF*2|@Qu&T44L>u>k_ zpB!O6d$HMXbe7uP<<9vtV0(%AF9bP~4M0MR^>mo^>2WvX*G$f3_o~zu zVJKk*r`DDmwPJ|tjk(>0!fLCw)eB?-;kd^ib=kxAOg7SOR}H#puiF@lx|7*pxm`dj zP8CDWu-P56xuVu+-cQEd=QC)O<55PLPF*VDtyB`ZQVg($t%KL)*(jc8SH`-60lpE9 z#m(79INML_!-i}xXN(x7*6Da9f&?v63E27Widno#Yq;bM716kyD(QsNPUOXqO!!L0I9o^<^bAcAR)xl*l&FE>8w{1iO7v(UYrcg#@tA6q zoxiq(-4b)sN`d~YcbQ;wpcOO|2&RBSI6VpeA~A6xfwrt;b~#N!?G4(iK&YGJqmaR? zBi8`3OEO692H-gCxf0&wWWqLH{ta2yAhF26Uu0h9w!@I`8}J2fht-a6wkm+Xmxw$B z<&mqy>F^tNIh2UsgnuvbcPK=^aZEvDFON&O2UYP@1MAFWQO=>dybPG{Wr7%t=9}V~ z;5F|Wrm;}4QKa7x;YGerFGUm`gKQBgh>xsa|9rQs0v zr_F{8&78cG|1jtK$g2@lg3@08dfN4tM);O=?22AC;kS;4jls=k?rg2}WN+@93!;L_ zlSNfMs-BGmcUz5@x0_#_IyM@TO5ln|jgLs^QBFCgg@#Fi@`fj8pTFBb{Ndj2ukY7( ztLBtW;TB8HmQ%~^RM=Q^U2cZcPU9oFE_0DpgdsG#~kFUoaHEeCf6MbL&{6i%8`v|{5GLZAv0+t zTDe3eml{~mE(3od#RAPVLcuhHLZ^;O4R#@2)k>s33-e!kFvg+|aUuL6CS>-}JN1FN zs&TI1*y{NAdbar@%>%(6=5T+Oj&PysaD+X`5S4GRWYd%P00oDGO1JJ#LLl4O(g6TZ~?vude)e8`E;wa(MH6> zB9%Fq1AH0JDRQ3f{cUeO5o%>Rch*X`7m0HkRx0!*x{rH;M({1=)zP9W_js%P=>d(q zxUCoghlyisw{5kk(5{$rsW=}R7qYVy7reTizQ0O?qNA0@Gh+x_geK82C1;dyjf($@ zzr$OTqx`EL|M}JJ-+w$E)7>zRF_bh_JffVXaIyT`|NOhztp-zFwGZ)1R$i@u7wWj- zMo2N4HB0lhU@!T@U%oqec^p|T48A`7^1uGP_uYL{&JGdKIAlhLlF=<7dkL)E4lmTT zlRUx!w?$_LYQbL|R>12e^W`}r*)5)MiNBY`nF$(C*4kAHla#&=wNUei4jaF;xhMtJeg!qUCvPyg^)cA=c?7vY;*pPn3k`w0Af_Sf%^fA#UjA6`=H zy@C1a+xz#vf4Fde_3YaRzxywLm|d-7xLP@0s;^YQ-||8Z{##ovmReDN#uTl&OUs$n z^FH_+uG*B&F~nyen6WS53+)Z~G)T~#$=43o*Y{UX?(XkwEiEs!>(y+pJ9BWjak$<8 z_~W~W_jfM7ed2AWh_d2>w$7z1tEI?nDA)+jpDr+3t?$n*KiU1_AAd?MmZsba+F+(b z`pZ%dVbC<{Qqv92aD(?od8hoh@$etv+~iuiPx^Y#OaiV-MJX;M2#)Sg;&Hi`k`3 z;? z;BN_1J{!x|f}Vuw_Q_(sT0=f=|P?cIf5Ba`r(d{#x!s!Vc)>CkC4VvoxJ_$pOGolTvdNk>YtNZP{>jSB$! zX4#_$ACwtXwvb0{(hB85lDy+YFo$LglPzT9)P(;E{KYMddJKvIsqkO9S~@Ph!Psj` zF>bVL^cJQRKTg+SGw(w293doC%X%ZP#7K4>d zHWPBGF66alqfBZ<0iy)_V$x%q%_(B;33`SzLB!|LO7w41&Pl(4?e|29R5z==^uhC;+U?o!de-0csUr%xS0ply+M`-6eIZ_%$UI>~w&}&=i)lmE-F&)H ze!LbsouiQe|Ffpz#^KZcc%O#D?41RSBBT^ujTC#Mq<*8Pme9l;>D6Xrxz1)53?YVu zC(*88B&Kp%@3zW~l8dO|0Ds}Xn6H#B{dKJA+ls>Dglps$unex76 zkzKK>KTwO`mrd})VX8ax;w}y}2fH5f5o;ssTB!TBddZXZ_OsLM!AkL9#n&&l9v}2x zo?4eH@jHW=r@QgPxnJ0Yiip8d4RFRr%uKB|km;t>Q@De)R%*s2kzT2MvZ`++RC&Lt z7@BgZj3Mj%;mZ8ojrz&T@MK6i!*08LGH}-uc%`pQvU zyUmxkDb^4dTx_*#e|fL^>bUu6FLSm=`4znfR5MxgenZwvQ=(-tM^8@ZwC^JDay%be zt<%>;@(BJ5{t7gc@L&FAz~52f__$b*-kKRa-F9_i!idID@o?vcQv{if76M9}OygAQ ze8|KCjZYhIB&O}MG0!w3`>B|gr3~yv%APNHc50<(n`|y?9Ca`bX`ND`al#nX2NHG% zQD2jk+>qWZm#e3=dWqSp#QsYAl}0C4>BO8j09KCSwKsdv6cf`-cr;UD<%Cc%Ls|}%TPAl< z@gW-Kq#}Cm#}DS|YIe2K{$>LAvO1_UC9LFmF*zLl^y&KN=Y(6^7d!Jr%{Xc z_mdklr{6t!_S;uq|NZx+qowZo&ck1S{`iN_&R<-t?yPn?^=7@Cs-?h@ql=^NdI!f5 zMl87M+-@(kl=atrrR98my_)YPQq^E?Cakkd+*XCdBn`TC>8K+ccSZds`oWgxtGAE0 z*Vg+x`)k{Ks|%|=Xy#0-ynC{Jes-|8yId|M5-A@UTk^BxLS zBQO8-%@6WD+u~Q*PV^xT77_C^2DMISe&+&7iABXpEsi zjL@{M=*7pCUaDX+CnmH1{Px|?FSafYyL(Hs>kF-ol~B3hFJ#M&dVA1I71D)Lh7vP} zLxaj%%=uUEu7*kh1p$tzk#E-QS9+4>NX1*7iv`mbe8_>Qq0vkdeg|XuE14-o)$!wxhEfcFLl`;mS z9H(*6ZSdICnS{4qOEV@0^y6ti1RMrBGn?{Gp*ofp4zOc*YH!*O*Zy+;GntTee;v>EOR<-EdUhURPafeAx=BNm}_Z$3(mky=J zrYxkqoqBq8(AZdNF{*BqlJ#O@(5~FaJRzXcpE;?VB8hR7TSvf&kqLjY!GZlz z2*VXg1VAJd5=fnpj-w_`YbBtV$!Ws(i;J2zOEBnz>q8VnhQp~BQ$S2C_cq!#ih0ydak(#f<=Naah#)k3a z4{ltcosxcO>Onpv8RIie+EnjTlc+@?<+LchdW+oe=(Taax8V{Wke6!`ULiRwfp~OO za8)3>ITY%ZVn^6*^w}tC#)-tHS9JgnoadTK{GMdoQHWWRfk}%3kzvv#8@I~!Nw>hR z1jRDjb9BmGi<&3O0X$a}Nl|3+o?-eOjY!}&uu|u$eDaz>lt1Y2{rvgPU%qYs^3nXS zo?6yQ=6>4H&X~G6Zk4sDVJ;UxS}^wVqe(mAR$N{bV%ziHNIQx0);{Xa?zij(i!Q2^ zc}41=R2P&lKY#h{KmV3khhwpT)%p8>|I6!t`5Dlu zovvI z*?Y@Q3Yma{<*A`-K{FXLUG=D`&8J?#Qjfo95KaV*;NY0gFcvhSMc;Dj-qT5@g0}ct zcm1=6)QpV!&Gh-Cc6#g(w6`)G_0#p>0wJlb&|bTEwt}6N62+OL0dut4!%g}w?8F+f zfj}djS(#-|1Uy|IwrRWuThgKO>WYJ^DQshejY*zvYMskM1Q?pk=&E_T(fRD&+E1T0 zPS#4Dk|7@$K5{{_vRk>oojKn$E?1*>S3ReTW7WWD(KBA~OqF~SMK3K_GoRn>esjjc zpzvOko(NpAPWb%gU^av4DCBl4*G`+B8x=okc(+43FyZ(<7%%)98wAV@-d$b zAzF|!jHiw2PPq2*cJI}}-CsR^{?oJdyUPrMomrRBtqO&3T`DhgyG*HoP9T^A2qpol z)=Pj_Oe|>2(_F2qr{qe3L?w`Eg+MTf%*+=EX5j)9LuZrX=|a%f8i8QRCH`vp50Z)K z!NV|V@|rCnTc{jOck;<@7E87xX#sOh49%hjiV-lza8%DW{0qaljjIwOEYsQTKKSY) zzfi)Z2CHq~UJf+VrLAsyx$dmRfSCAp69Y4UrH4N}pMQE-Jzfz-t%>#4?CBsr$l3}{ zd(L5q>Psu-!M&w$H-SpO`}xV;pPsNsBht?ihJE(ar$jh^{y+Zl^FROc_RIT=N9)^n zc2Hke))waHTdl=e@OSTQZ)tzAI;era<%P=HUEIs_RHhe~@~KudSac=I{&FipycGO( zVodfL0AEhviIA0p)A(Gk-kqD-*9u|YB2FB0`yI$7C$bh!Wc`1Z4V$ItKIdH#6q_~_u` z{=H|9HxBnY3v;fZYjL&faIt7jY_rKaJDp4`rFAR0ev9PY;4dzwWGztX#AE!Beac+P zKT}WSkd8}{GIorO-tDv9#k~c8DX1iG?oycDD!W4w4qL%rfR%nHAeak`VOpmat27Fc zL?{H9XHwxv0Q|LB)pFI)2j#<{mGqU%@nG0aHW|sf)vsZiVjzoCdhd9#+Ds5Ba!2%@ zsDV0;`JrlIul#|njD$|Hu0V_rDPHnCBz+d82$&eE`4mqhnaJo&LJj7!PoLFg=8{K+~&!jNQA;Lq1m9c;22EYOSf>Ua!$7y9mcD@4GjSPwEd)ME2|Hiu`LSjB2 zfQjHcA5MUm&%oeysAq6&QYY6BMXThlASi;^|sky~~ z{rujq!t{Q(fT7o1l53bqwd`A`c4;JCxgtR z^~%%j(u38?`HHC(Rg~PUy{=xYS0B^ml~;E{`uRBgl(aP)GsQlY$R(5F)k!%GL4vr` z8jC6z^*7ry>XK8IwSc))ZFu^r>9k3jG4m#~!peTHvfBlxgtqBhG@Cl)Ccoa4cQ7L! zJl?FH_EDi_Rkw2`pE(<3&j+4`)Sa)-fB5HLlW%Pv&bv|$1NJAkj@%IGA;6csC*TY6 z6942@W0=OfV(}S)V2CgPO*0bs%X*_B1%?RghBGOlN&x=Kbb=xOwaJxQkxVtE)<~2} zi3azbLZUb8}Rs*8JI4Y>v2Q zm@J8}=yT^imV_1WbiPwy@=nlI7qy*z`z*Ck_0FbzOC{ez!M|9fg|d9KhzP?9jQDbc zHIePR3$gh${;Oau0RB>`F|*(HHzR~qlZ*Mxa^>l7U*di0?aZwoEj{?+(aT?c_W7?~ zfAhOSjMviU;GK<<0)R2S@$EER)cg zYN~`>nRMmw={1rBOIP>(5pp=HWvcZaWigbJYD>h@ROtAKmN_jAO7(-tEX!m8~3)4o}BL9Ki)YzUOzd! z`0PcYGn;SI3{py0QUs=G1|Y4LD+ckQWo8qxO30seTWC1JVwo_3!m+X&{%iFqXXmob zP7YdHpGhwC>-+o5$LD+CZ)K_GVkwnfsxhF zqUeq0T+89SfOt>v#2{!0p2W0y1Xzy%%5dmRyj&7&2sssNI%aoSZP4+SEolyIq?-Y((b5s<7Nwbvkk;eMl~M z2!eEOo%c6C*{ba|+;#u#(cI&|dwuVZuNd{NeRjJ1@sYmd+jx1ed$w6WTAn>xE^Krd z+6Mb|`n&wyN@UPrA=-4vF7a7p5xXkpG^K;^eOD&R%0IbT%kl-O8IGhFZgDay@J=f; zzTq0vT7(g{tzS@-0uWD_3mfaSY2T<-F=CX{55{hKfkXEJTltJKS;PtG$2U8ga@aac z6@SFjE4n&4HlI4%SvJF_kNcUsOWFIY6fE18itNXkE_w7pi#y{7g~eu>%&zhj!Zcq= zXub*=M$M98p>Evit0Z(mhr(qRP!VI1dzu+4O;&$+4*%_c{iy%_)7sY$W?$XIfKAtZ zW~b+xNnq<@QtXI0Y&$Lcc2m|#j%1y;@-EBPY~tx|;nkf!>)sx$I+hE-ZfLz4*_`P- z-`o7*(ZWv;mVfhT<+o2}UmeySZ&IJgWC0CyKs;~zMt zD5#u!d2su$U&Qw6;+SqaVTf*2+V|H&wQx8+)a96t(VoFU*`UEfWt&KSdFUld)M<|% z{DtT8I7teS7yLzqW)ubZ!i%xEs7M}B5$4t6>7oKls+^Q5hXR^RCd8R(9WEnOlYr2; zbkv9`Jz6e)s5$cFUEYE_G7};j6)5{S=!8iPD)+y6mgyEae`3?}WLzqrns#d+#m+7z zG@nYzc)x%K3!0c35pmKoowN$0Myh5sIj^}A)n$E}w1>F~_>2E4FcSoV!|hmVF~4}R zj-_gyO5tWi9@6bUKRW&7&S0}M+buxWc8}NhPBwN=wn)6L?k;Z~ZS0@!VpLw)TYB)x z`R>^cx!0xr0g0r>N*&o5Bi7>WUZxofWE`bVrbz)^*c9^Ufne~LK_RevNrAZ^k9i9D z=zPDivN{K^%$E~bk_hQwimo;Tis!STRLYYrg+Zl|OY89)Vzp@VXyBd8xSLFQ z05GX6VkCuh!z?uA{qaGC3_GR;)}ZJ!9*p$hFF*|W<(B*4FD;$4Y0aFk;h6-563?dpFU2`k|Aof*7~Q<&*)3R6GdB#H*BB- z3OjMJS0IN)y(B?JRA{AXvOJfFl{`k5l(}lPo&bMmXLCDS1MruhXKSU|*_lhVGdhn7 z{n=ubk}6^pD_4zK-71?$ZE(ngX;+2L%udzjvUmb+@HY_j8jWhLZknF}0yveJ&~Ojs zrfxlcX;3(p@XU77z;3mfIy_wqrJVdF^GT2k<_-t58!bb~C^1c|>`JC2EHOc`5$Yy9 zsUazz(hCIY(MZOr1<)m=RD>9Re z4`)>$5PZo=;g8@i;5dZf(GP(n0#r<&0XV({WOIma1a1`UH*9)JD;_#>ZAx9#PDIz%O--kUyS&NSslrx7 zOQ}=q&4p=`xHfhJ#Q-Z8HlAsXm_ia3F!AH!+X39U(jbULzr;p`Z^;Y`;9}eQ^g;Q+vGLd2w2Ov{$^prE8{ivq^Mp$9&N>CXLYTK#+wTFs@F)A_Yrpyh`MyNXt0Tnz+A>)!Th_s(~B!}D=l%}eI!*fxv=A-oofBvF$+Rq+!7&M#bGpu3a(ul?hCcgshgwirC zFipt3a*8O8IlC-jxMH7t*E}XKI)cZo?q~a*#~XaYz*aT6*K(Epft1q~ws8>u)LP`Y zG#La#goj+%FwHFp%k+whB!p=27yX%2nL;lHg|U?a%1F@6fBD(ssix3_(>0%msvoIh zis=;)4F9$8dwl(StP^3(jqRUnB zdMiF|={zTqM3SqpUM+9cQ2>rVJ?X49YwcWjzC2i}K1A##hs;t^V^5#C#R1dEF9s_-hT1pmoI;ORcz(}$GMei zy6D4l3>hcX6Kf>$^ZCY7HO>-nr>wq^PgE$v5anu7=DE2-q*hCVTRMw`D7wX?PFEwXMMmAE87=VNP&jC_o0(kb4KkBe#vf!L z;uszwo7Jx7_7Z~2jaV}8$yI{K_qY8qdwssNy0_S0?=Ich?CmWgv&d}`efq8zR90`Xk*|-Pti~gKXdJrohzpG+JCo5jedmi3szDp_3p?O01*fV1c55P z#1I6*Zd_PzX2F-(3O-(v-%G-KiOW2VCtp4R>V4VO{I?&z4LV=ui0Q7R#}e|(Vq#2O zVC(QTNCluFEskcN4fT7dSHJlru;!t}edCRwJp!A4@2zWZe;~XzWtJ)Mg~n`Gozw4{ z1Xt}6$`km*X2lxs8rMvLzt<;+HZAZM8R3o78!PoNKQ-*uMsJ@MurrY$(uh(>2L)s0 z3Dp$CuL-#T@MX;_TPJQzUA?XrjA*71qDNGM8_J0f9=mY&ALo$(lhSY^Cc|Rn82fbPkQSE@s0N9sK^;oj<-f{^N_{ z!X zWi<2ct90W;mV$9hrJY>b?aZ@7GaF&c zKsX+XCt{Ik5d6hOtkei7piY;fbYLPo^FzxQqp6fH9JW(dK=e3M4Q?C^ToFsHTiU$6 ze){On^6B>AU^Q5Zl6sSxrrF~uloR0@S9ujEEzB|q2+yuI7PjV7xeznuT*4a<+QME_ z60K2>i zS>`@>cx~v(;3+r`{xbh%+Kb=}{!*p&;fKFqn*(Yvfg`bAuJ_s8sgT8Q=j(#V9DE+g zJ69Lr?}xYE=X)U}MMCOb!IgKWuE>4*cc!oV=JMC9(|@ZTlSHh#wCAc~0)VDScpSl^ilKPYwVa{$FWlQzTm3fZ*j&wh;OI|A5C7l%3>(- zjb8|^@a5hUTp@45`SzN8?22;yx>3x~Qy8$qC2u;kS50!jmu>YFBflrUa?3D5245I6 zNGqRzqBKT}xAw)SRDUL914swUWhC=1$ITc9n3hFY}SNFk@% zs%J%oLamg^B>*uSczGO!dCaSax6*MTEP82)T>a)z{&<-TFEBUaR8M;JH)(w}$foRC z^3kM_s4Fp~gOq7dL5X9T;jg7ZjZZ;W3NbPUg5^~|`g8lmZQpLwvRw3T)-CfH9+Wuc zZ;kwoz&!M!g*s_?1Z2dTo@0t@0hpY8#m&F9;+f=q;UoLbZT3HI;rn0x+aC|VIiI=Hm(*PGqh{;b*4@AV;@kiGKR)`0@64=a_o&TY13*uym(^#a z;12c*yaL3GdWV3k7X!W=|MUF!(tiaa1KGpEt2ePDy<5qA4a29(ETjKQrWS+02xz!O z^kzoPMul0au&LY`pD|)J#4LECH~`#mJp}#|5sEdVJYou45k;ewSbQc{Uz?ph=ux1m zDSP!fXP}$fdwn*0XR)-`(H7l?if@8WlBkJTE4`G6t^iPOc{ai3tl5mC8zZZQ2%w7T zgUtx|%gmQ@lF(v~NIS>+$A^vG4jSy&zkYS+-qzQD_-ct?TrEaDNN2e@JU^G>;dB7& zPG`_KI@{m6z1Can(3VM~Z@Qjf)aZ^FB5zuo=tKg4J1Y%yzySVw?J90LnR5Wa%zuX` zYQKd&k3cYLD)14FyZu3Hsgj_ZvDGXV3$bpm3iYNO3}>LL6wt=4@~{Ej>F#e{EWJ2J zKu+wmSk*Kg(2iI{o_bW|(Qu5IriCsI9p-%dOvA%-1(p@!Ohb8wAoJi&8f9{Bw^ZpW7_J~`PY%OdGnLGQh8FTlnC*Uu#IkzkoA$RCh35n52E>f zv#E?msXJou#m$L=HwtuT{N?%L=HbS{y~FbQe0g=2XiKe2Pp&ok^Qe?4wjL%O*bYq` z(AF#Uo%yZ1TLh7n%IQ>O0{q2g%}EK&1$^PZ>@PDi0A#re=>Tdo!{6CTCKL4pyavBV z&-)uQ1kf8nUY}hR@fapdV^*Uup0sC60fS2}RP~Li`bH!jxDz>`azTCp-(F!iHmX7K z0Gcxp1|%8X7Jnu(zr75|D(tKUDu@#VTu^9{fAI_ph~kltYP{M}{TMs~7JM7=ZKRW6 z4Ir2rf@aAAH49BinW-+ly;KV|v5&zqAO9D(uYkPm!#$8tppansf5YE@6`$WOBJt@i zwPilkCGEXL%N8|uWB7q;$vaE#AE7P63VeoH;lW0m)t z6sV?rM#z4lvSKp2hueW*xE_Y9F0F(}s8+@3ZOI^2 z1q3$UlC$Q z+f?zczdl^~XwNh?k=id#pU(xBBDK?*;(lrIL8Ed|UVXUq;g3(|@6W|HQqkRlf2Xhq zOZxHo;wQ~Cy!9_0q)r3}#oAumQ__qOTe)z#A1<-^q0 z_j}p;cMynyFH3GWuzb`@o}yT!w;EUk<{-h0SQ(obuqknLx5@|Kk@t}C2sVwzIVuE! zU`f(NiYBgaz7Nn|#@~#92PtK!r1+%#8$@73IYR%Su@Y6J-H6Y`X!L}%9bN@0G_~yg ze)U+|F3LJa(zaejza>3!^5x^FfAwY4m$hEt{cUbpr%yQ?wWvzL@vLV!WO2?Hg+T{< z*8Gt)pjn$GmzRT-n94%BADL##!`M&vkm7Ia6Kfxh9%W z`In1@huieJE`I+ZHLq;bC<=Zuy4g|XYqT#SU5#9? z$B5%@JU&4ImZKaISS9Zd-?}Mm0eNR$-O|rw+j4a?1i@^kZ1XN3~G7!`sBmkezf=I?!%v6%BS42qNBw&(&~}Se0u!#fB9pm z8pe+bsS&A0Ah}Rrq7@8w6<#b57OLA6qE#aRH1|M+X#7{qg_))`myd9DihHHHF=oe? z3rYxX3bOPyef#v@Z(gl^aXxi8FZL+m?Do7nG7}F^$K)QB#3>_` zlKmRCZ1|>uM?xp9d>Tc-Y?}>JKVdGqSa~KrTj&}e4{Ky`gKE+-`@z=wo0FYS&Kl?I zCok^q++90+u($vG=;_xV?$WJUi{l!a->4@GF@MyhH7k<&2y!&?W@VvBX>uU#o>{Fx z+<@Q^vE&Xp_*-AAqDwR80BXTs1m`R}GNd*7OlZ*z69Hd}m0`iu4S2mKaD+J~p63d+ z2F1kOY;kHj%S%9ZA~&D#Vva;g7^`C@w*34M_1M0c@oZN(UJ|}BU>OU|rv)}yzey~x z%KHprB7Hb};CAL>q{3*JWjEdf7k1>m(SVW*_I#BpguOXRcoWqKRN7!1vpZ$ruUbEhX*ry+i&1J&>oGWI_mC{tL%=~vq&^aRNy!`3nQ(N8orWWngV#G4&B;L3&S@afWVvyhE zorSHV&DGttST63##r^q&)@_kll&H16!uDYaVARGwb#=P}{syX%iIfM`eQAB(=eJ{i z4!Vs_v*Hqe18yzD-)bS0iZ~XgGqcrXk@(F@s#ZwMlu}`jC71R_L)NK6WP7!igP6PZ z!3k~5XUee#Z4}b)P^mYykwJC}6+Hu^w;{hkFdm5!xnO9#xdq%i+QS7#;2#FUOdc!K zNv;;^dgQ{`RL&XqW0Y#*2n)6yH%KcI8sx;(@C!~p0R9lX(8RiS3%jp(-JsqG|1&5F zodkdJUojUGNCx15tQxT;gi#9oWuum@9CU2(7ys2I{{>0^6>3R={_hD_;3?uWAMg@? z!Agd|ypw;>q`J48yS*F?(6l)lG@oJ1Rp!57E}WMf52_pxqH#X6N{!~sHqe+sLE0f- zER9IuFBcyK1n1*WC5&PFy_R3R-|;>?l+DDuA77k(_Rv#}=%N#1x4um?)@xRfTLqOH zSIb&jIe7E~!5t&LO*NZRiGem)(#`H>W)~46%|vS)W`tu%P|caQoHaw)gtmt_a}5eOQmc;$|h#U?+0- zjqwgc+M!HZs}ENfK0TTJ=3e=`d!=7pRHZ%tzJ|8z1dVpVjYtvJV6|?#*pHS>-`;J6pPFgbu4qU*D(d zsQPq!>DBSZH;?yz_5Ab?pDurLPJIB)^?VjGlSvMdC%pYZtD=^YR^t6WGn|*$4Oz}F zO}I$+5;^rcuf2)CgFPy>k~SX<#sWk0Fw?0Q-;%N0+s?E-d$KIcx+(d+Z5{9P>suUh zDx4%)UvRbv@)8}%OMnp_aPPIU@Teb+SZP7Re5GW)krkvuknOFF*B2{aKN4o_bj1=8 zj3o*AeJtk`q-}dmf5VcQ8raGmRb%o z8&nsif*mFN*fc2d4**|UkidO`TZ>=4S2=vO`#LO-xj(Sm!t7orY?1Z#)An8pgfG^! zAD8xhXw!7Sy%1-xOYF0@dqQtI@p^ZLEU^y&QBPcMjrh7!`UirA}h$++)ntZe2E;ahHUgtvoT zZpD~IY44R1;5^n#Xw}4I(42H}@K$IoL7)ySQ7jf1ZOP8H;s!!DWVYS z6Bl8yOuH0Dxz4`9h^|r}CcB97NvV6Qq zQWGI;``*M#r#2%JL2xsXS;> zgv^GN3oKK`t*VsGT=GGj6DyN6j0C2m$=UScL1Xi1jWk6Te;~F87dzkm{>y*=U;f?U zgWYT`K_Vh=F(jvp;g!94Jkr(0!gQm+T2Lfn&*WVGn8}}_@K2IiNG%>OlGMSJ6E?&> z8P3}r`+5yQpV4d(!%EMrDX1k<2gZW`rvrvqANl`(5pVJX)%Bf)v6$s|@NhE&>7dN-Id zpo)MR1ga!UaXne|I$2~gHM2MyO$G5JH-n){aZVAu-Pv2J&lM=@ov!D%b{cqwmzOJO z`?Za!;8cVa4ANsnZhXAsWGvgwA`&B=QG+R}PgMNzjKdPZacGWC;)PC8^g}b|z-TMg zFj}oZChMX20Pc((D-w6oT!~B2>$hYJ(Ma0IfZ*`q;o_a;#B>hjd1h^fZ9zxaF{T~k zXOa^#r#=mfO9?xD(3+?vSWnAb8fT2vT!n2yABaql8;Sm$3R)+VE{8+r3hSBdlO<9r z_-lngF+Nev`WtikV8n*Mi&rWfwx#GnPJ8`6qtm8vJJpe(B^$F**u?G&Tf8BkR;Qzd zlLdj!%VACTP;1|CC+UU|JsP=_Q1pcs+<`JKMg$xYhPv_rT5Dy;srkuC~w{fn!u@6lY$OqMYm`=l)6J2uMQVZ(KcWGv}w)rvb6qV|!&_P%aT zDST0Uf6&q|&j1`$I8HG0Wz>s_I#Nh7apnirlMF_Ssq#{Fa=wUB7WX(m$>sG=rzQi6xooj<-R ze|@t4mmk%>eUN{B=)1c>5LUN~&2}Y`hDyH*A5O2f7sK<~)0Ok@PNz@H(`TiH=Z(1! z7HSXbYaeeH_DkzeHa9QU*Uy&co@_6FbX<6}IsfUswO_ti`06o1Ql$?Lawlu+pFKJK z{TGeT9!jU9s>PJ$&eUMlC-Yhiaj&bCwC1Dq6l>Cf9-CT`^tq=}=28?bdeo*-8k#3+ zI*-IQqtLGJ)k@*BD9N4bQF5@a3OnEFz5b4%OP2}TE15QfY+%AL;e=Ws@nb;3ixS4im_*UF!|%jWdav4-Z$~Trgvm7d)25v}!6~nv0oP zn2j3vK35f4sIFyZa>=_1>8Kvov9rB|n9K4Z6PxV1?oELh)( z@np(OxZjvVWr;XMF*`{k6VV9{w6_GUeVQTsPBiEZO1gVS+lbjA(PGS_ylNU4Dmy)o zmV)2h&wT&T^I*limal(!r}kjeyObj}k+mSk@&5H(>Y!dAzGJbUwemaCoxeNNvO={tih6h(et3v0t(# zkLD)E`K%FNMh8Hzz+Z_<3Sk#JWEhIDVZ+2@#Hi*bG(HtY6~?qXvXEc<@F2Zi3$GV) z$Mco*Rf>DKoW+1XX63hl|4u4}E9-&IP`IFuS;hjo0f&^rkwNpAHe@tsy#$VFmgT=X(3isi1ITnZ-BWXKWCbNsd-}!_2t@|6OtX8eaV^!dPzQkX+(gacb z;C061a;Ya=YSM<|31^J)E)P~V0xV_6))w0;kg(( zzZK89UxPqO3$s`=%v%M6V;UhTqBMvIIfV04=uGzV$apV;Gw!>ay*D$p%T>MYw*k)SygvPUA$sj2kl=3Kp=Uth1IJm0yqOs?0${N(I%89l*W@KJ=p zE*Mh)XV~EKs5FW`sA6_Do|;QcZYW0H<>S-0LG zGFhb{FKMU*k`v2@Q!beexX+bFJ6Ig($&O<0gKShnm4_hH+-W zGQVz^E~=y>G@J32BB9BM)njtNe0`Q!%oT7MxCy1gR`SXMadWAWqF=IBi%nO;$&e+V zm{^$25j&YJM={6|ArfN*T#BYs9^cy|Rwn88*rXaNGSov#X}3brCzbbzWZg{(S~kel zGlDg@m3w>dNLN#FZNJ(qIXifX6z%B}0~ci*N~ z7^nqs`S?&>jAY2*GP4@1Gh=SR7x9@ALuCBQ(#-j*2eER3V;Eux_{*_}7lK#eO6OJT zlDTWKi$rNM_}enn#tXsrbW6|8mcCoOKwZr1h20#D_(8hP5LiDtVh~E)3MkLai=Cst z{bcdSho}GkhwVSU$-dYl`Ow4Sd5w-bzq=YEdC!t}x~6j*?#@Yhk>)@^5Z+X z`n(^hQmRk{_no;Z>8a96ekpKH8~%xaZrQa;_KDGa>6zT2pcf zLu&6_6bB1sbIts#?JA|lD0sz}2Yp$)wUNgqj+)KV6Q-|0v$R(yY8~%G&|~hvWEn5| zUnu$s2_Y#3Pt?!Hdl>#wC4d;)D(dW3_LFyUqwBq{@$Ob(8`Jr5zou}u)cE!y_xZ8u z!F=e;vzfpAsPVg3rB6->qsFP5ezd`-&Oco7@0G(x)1?o#Cm*g8aY-w>b<&%Eus;9l zm|C9@^>%B8#SgZ3K0704WBG?i813|nG5*(3Sk3Y;Rn9nj7hml&*?&iTlc)`lTA#C1 z4LoQQiX9?X(M68v(#6V%UD&GX)YC#Z9UxYbS|4h@fBf?=@4Y-4*A5zN66#jrK2)S} zkN|&Co;jaiwg+DFUlJqLK{MqM{jw$;E5--^4Sz4mFZ>s64g6)@gZ?HUm@Ns$TR<>x z*@)*RLlz~O1I<5h`98QV{ zvlRR0?#wU>S9>(HG;&r^d$q-lDi=o=u$V$U@E3iR-B_qDZt!up3giXHvA8qzWQt1j zU}m?*M8=qQ6!&JJ!&C`FrG16aoqIb^pWpw(pMSdho7ymQ1D|ap7tVH?pao>3t;)T7bI49?X8M)Y# zu!6rhuRvZputfAvDY&;YgPZ=m|36V5Mpp>4ZOl(yC;AVVR(4BZ3N$?v={K@La*lAgiqTp=m<7( zC@^QRd@cY5=EVhnGf}JlZSJT>Go;iG(PAtZ?--JHvL?{nkrxqyK_yTRdky`mz6~>@b<1_+omw1O43nEFOHYTnCSx=v`uWhXDItW9b zU|$C7cc|_gTEjz^U&KvT`dD$KydSK`&(Ok*`jSi za7*WV*E`>B>Aitn4FGDM5HLlz-(s@dgh-;H+nXy+kXFbhG?uns$S<}o%vA7Spc(y{ zi?yR>@vH>v21 z<5OG;-N^fB`1}!A=X$sG-AlVHtQL5E@7B++cVFi_FVcvlMk&w?&*hxS#h2gKcN>_7 zDRVmF{XjDT+8lV$9J<&kGme^aj>MhH@|Snle|%K`>U`?6)5MdF>gyBtPSv|wa@OLm zN;I;Pf&EEBs=z|1b~gR^w~rqD`h4kw`TTLNdcV5=_0iVn2XFqT?x+*PV97h3Bhhv4tMEAojPIr zTbtSYkq_Rf5%XV$%t~g#0|r^RUZ7Zzj4Aa(+PIwO66W2u zwPNsaK60`kuK2hV^{{d#G(KrZB|v`fGK{dX!hWc_;Q8<$f3@-L6KO4I->I;xGlsF-udAft4V^ezSAZq4(pxHcixw^S!;plPU+w;U)5gj zefUq`+ZJLJF|gKJJ!|0OrO9YgXvx~y7_IlFXP>}7h$t3?e+-;9nA@# zLuFu{C+1)wXjs&vloDLucd0*vyqKRE%(4871dTwAKa;nJeyD1oEhbMQpa+T7Qqx{4 zBnuh}%&#QBFR);hM}yIba6*!}#_XWHrm#`me7rTeUij{MOa;G5ln+7Pa&TNx`zs`^u(#`C6BJHZ|)?xk4@}s$gD({tNT*QM9 zdA0I{1Fyc|E!5)Hv)1CGFk2GiT{bBXKx#G(NerX*Xuu)o8ue;bNvC5f#;u^&CACe5 z{qsqE(xwUO1CzdJDQNNQs5&B-n2QNMbA0}Y`wqe@x64T9#%;?>PhJ_WmDwW9!zMw9w?3 zT49nJ4rTn!8Y90I)w&t`T;Rx1Kx!pL+DdoaO*-i5vwH-IEFG?=7K_BQuyrW5D}*M=h)zW4u^vz3 zOal95cC$);+S0wPy+?YFc(Dd$ z1B^afI&PCvd%LUID8wihq~@Iv+t$7oU;10l zZ1@fur7}7(S8FXM(RHnWM8wg6xm_i?G1Pslw+pcyH5)@3Ay=%@T+X=3+`xwI2)V#t zC_l)Hy51b1zfJsr+afiCwp>tJjy({3UI@PP*vJ88D1$^V0cV^4fbFnBHnUn;6Jt`3 zG{MReqsI3--X}+;rT;p~D&&e&1*^+iXP<4ZeRHq!>LBrGZR*X*^0$x8i)kGteZ`<~ zLUmo;O;MeHDKYnGvHoDbelfHC@y4T{&Mg&VaLK>($@cyiN8kOgzuWloEPcLMc)q>( z)xCvp&T}6h6u-W|_=nd!fBv@i!xPDJHgG&wd39KSeHYAyKU(KA`dW;E=GI4#LQ7N9 z$b=;1AeM^UW;UlJk!JhwXv8LpyQLwA(r(0aCDbcM9VYOXi>AdvatLD+EE!$m?|YKo z7On7Sqa72oxz(5V1wP|Qz})ZB61)ksrXuPRvY8rVt~Mt9iO1Wir@Q{sCGBF?xLN>$ z^H29IYek5yYi|l*4W2DT?=2?S+1Z>VGfLo6beM(QY=c{s*uiZ4ZbMNEbw%|fNxOTs zq_0Mn8i*N3%@tDBb^?NdN!4NyqCSdNz_$fvFMr0fzI#V{yE-tjnB}_ z&xWj*;yi#r=GCwglDIQHUUJJC5%Wn+x|8!gUN;`srP~Gl>D=UxPqV*$7Ww5P^Xogg zHwVd&_bR`95PyA;`|>RN<^;8&_SwCaPw#7r-k*!xuF1Rl9TI86D2!^y5(a%e*dJCI zXM(8Kcz4sgmCDK7Wi!bk7{Pgn6|L`NlJ({$|QFhPWU$hk`0&@|2 z$z?4#x$mV{v&{Z90rleH-1hy|)2DkVe&DZ4C&1%MnF1Yxpe+fLLJ2un%}b{eA~o~mth?68d58H&KuI+tv^y`26%YXc@|8f7>-KDcN2y$&_`rz5& zzx==d?e61!BCjzRgAPCyes6(!44zwDDnO#+i}_|(bx=R(l(C`1imPWjNf)7KHeDjP zxE>eyl-fy`WjgGr1}$a($@d>z{O048r*}MsP;M?yxh<|LroGT!)_-^l3wFFkM&`ey zVPNiEKU_kfp5Z6KZ_MX|?7cb@CU%y+MNhaEg5{MPIeKp$Ryi|4-f~YyoFt49#WEDK z`u)0i+?L6?6Ddb1LUWLs!UC611IkB>q2;@)Bw@1ZJNI;N{>7nxqqOks=CjHsz_~Kq;W_?=c(pvnM)uZ*ji~Z$;wLJ<+x9jL0v_T0>5>U8bCFmII zHU!Lg&yd2%9wEg&u`pR&u1+scfxn#VW*3Wvj5p*|m=x6Jw41F$iUSJN%O#yk^#CPMLfxR$Hr6Za9MuktX$Sf3 zc)NUr3#*U2I#+XLX1EJ1fMj95Z4McsT9SU|)b0FcX~#iHh#UGXsxRCV$=B#K`6F(0 zq%L7Q;A@N9nHuA8zSVXUlNB%o8wF4Kjl0QGQs-5O8^jO{V*Co!!WLVHd)Phc7B}l} zfZ!%B54N`rw1Bx++uj9#k@66qFZE}3g23PA@VBi=Z+RwovCxfyIYzF)oW`!doc}gW zVqHykjQxoXAbJeDSSfC63ekA0_$$0#e0CTsiZQr}TnrHNggGs+sLKu%!(#p=$j(&v zT7Mg3a8N;==|`-LHEJ^tb0gFn4~{O9i$zdYam@mcNF5k-V#=Z2Sy>Zr|z zM*VPY?bV&5uTPJ@JYIM>S2>z&JeuKJxL;d&G#_3F;)34#{B-V#KEaIG)qjRCC zO!>iIU!$VUg-Om-W_;p|w=ZB}Xif>EM6Z-im?S|L;7gw%Nmk=NtD_Vn|G8Bq=r)YC zXh*qjYeuk9%{<(LW=6MW*zN5z$^l#;7`}`ZoT3WCuaq%2jrLfZ4C}?AoU0|El~jVZ zjk35La4zT4_m**3*>+0thpWD$nzH7TSKNl8kN5(HzjVA>7gF-FPg{=y!DCsMc{XL3 zing1@1cfm~V|!O*Co;$Z{?fLby4W(V6bYX!oNq0^JZn7KmpU~Z4!efiaqv>FY=~OM ziIxu-+eTaa^&?1{SG0ZoN&Uor#eFiZSWerIXKnWywudXh&rYl_cRZh;guZ`}`e--% z>EX;zPvdWnvR~bU8pogQn)j-X`Q-A;V|ss5+f|~8AO7wm0N`<{^=nG(usozCXGU zcUQa=@UfI+pbfSXi19s%TXc4bP})U5IAOdjS~deGiQSM5UtSW@?}j^6?CoW|?qV1q zCJvgRF#hLD3pA=)(|q-|e*ut1J8k+i)kEMfVm0{7PcIjL#f6y3-9u&=XAleu^OnL0 zeZasB*O_yVdz1uHJ^IzNzx$VeS~y17%sv zq)k{ULRvamIsD*+*hvh}5Z+`tLbWRucwhv}M5#)YSukl-NW@#mE4ybKjqN)4OGl5x zq4MM${*nh~SK2D)mb12~r8u8qpBm)lx@5kPU$j<_M~~K;Ogi#;Z*I~XqpT-n0Drwf zeLC+UqxkuEFFya9?;rpE)9tSwk$6-4V2>Ep^-mwHesWH(izsTrizN)16loWom{8rZ zh((rk!h&JGuwX7G#m#Wq31z2QEQ{OqlYYRunH}U(5rJ-Mq}*$T?D4|n(ZWO}1QW!x zmaZgGZY^FD>veEjokL^x7_B}t>7cC1Cug#eVl0pg&u=c|rt?eC(jq z4bFn6v#xzwnX3bDn7^3K-6R3#N~s9XeDBy1CeMSJDcDFVU%n$Hn4 zvH5GYN*I5TJIZ%2P@o!6B-Zy!w0#myzuGh+R}YLb{FQVA#G{H%p`u%68a8R3#n%A_6zd3(+LTOR->7<=5ha@}cm{}__p02JJ6SbI=kysO@Z#eyw4*9 zjmk&xMO@-9(160(G1>+HMQzY{EC40E5>R9I3IszuwN{i0uu?T67wYKhb4K5 zm0OGr*!x8u9WLlWqx=`7Ot;=@>+ZbK-_8f&E8^lq5naN^;akBJnB&1^2l1uL3---l z0iEyMcn6*f!)*!<9D#J|F2%#_RIR+ zQsTw#{@;BWez5xJ?>_s@|M3sM{%`;A^zXl&JYUP6t|kr_#kAG40)JZtKwk|tK@^|WzsqlC;)Dlg>KWn6i7MCKLoVgy0swSK4n29|YdM(98lRj!K5VodPB- z?_U?TUKwwHN7C}Xd2l3SHa24N*{FTLHgURu@;v?1^Yj;I(O3Hu4_2i0fc>B{{ryGh ztNXUQvo5sa`%9YT42AME%UAC%yJwnVFg z_A$VMjK_(LquD)V7b~q}bis_v2k^Rp!cFj%3kV(J0)kaCfk4=8@EILBKM)N5Y7FBf z;a~FK=39)=Z!OSZD;MU#zW;uKzrEvBoHu7%gX2B?Ef9=MO|NQG##9Qq6b`vLVgX6* znF(gH;YM=$-eO=WMHQpktB==Gr!VeSmWqzBNnsI_>6ciVq&Ltz6?K<_VOFYZF+<1% z787}m#hvAD_MlyJNl{2Y;F9;*BqGFZ65-Idi$3tzR*y!vD;salawiKMZ_EiBt5UQ@ zuv_}@lSlVId5G-nirSd`0>p6P(tIvf2!hC&LdYL;ENo6c`shBs=-R?0#3vecU^1tC zAv7IE)t|XDot%!>SIgip%nm{X^F?#Ur~~+d*Nlw)0c|L32!;*OxP{B*S2JhiEvrEB zndIF02A24f-+zKR9}k0Tqv%-3;^knRL^L`A)!}+i)=0d{t zBs^Sx+5l(saKrhXM!K4zvv_fHfkjTWUKvRF)HV$i#*+xGY_HutKSXDy7iqeZnyIFV zgj!v!E-#c<8WrA_@{vr$5&%~nQdIg;lVHp)j5lKS;~8hdh`Q?!YT|jPGi!~^g*^r5 zxN%V9643&qu(A~;QR;^gXS4>9*Qb}61!{-L9@0+4j5IDWzt($|aO%iZ0;*0Pc%TqT z)iP_xsO0mL^#Z@_iQQ>aInZwv4_U<6^P1aFGs(%lrnbNS;&|oBL2+j`RE}q-v!tvb zdW4fssJhE2!up|?bvZ1<5pJF<`Gx&DlLdRqLGhE4)i!araJa2c(1c(*uMy1kCJA=6 zCiqJG$Hg5(qEri2)g)+FSguzY&B;z&&AGFs!Co0;X(~_P1aY z5-3MlP~x`_lthU|e1_`67U92;U-p}5#l1P$b+xC3f8SJPJKqO$0blfIfSAXavhZIq z>b=yT8T$gVmxu-{2RiW{^GOM@1oWHxyd-k8TqA!H{rUFotDS^TUVjf47SEjLObiGo z1e9l`!=Rop@ujKkdY%|(13m&OG%Zfe@?yHqnKHAkC>NnY^lQeivAb-Rm{K0vY{zWc z?lHljXr!yZ7yQLo#qbyZ6;B3@y$Q0tZMeSqE@2xZg%aB*=La6!z4p271sqn)e_5Jt z#wE4!&lJ8BcLN-Z&~Q z?B~`V){j11R+@VotEo3%oj3NU&%QXn`_04YhbvG1`qL->@b#mA{1y{Y>dD6OA3vLU zeZ2ko(cND^ee}mqoMaB?CX#oT=~{BEl$YN;nSXVWK3X47dff}9;OaDS(CE)2ai=ir zHO?1$UHW0OdO#(?c_j=?^cWQ_N)gLM40gwSrf%ank(;E)-_{OuXg8O`9P&BX)3Vg> zQ7f`;JXdYt!5q4ZJ${el!p zI4K1t(|}M83Kv{kwb@r^9d`N8#yW3H`)>@kjE)a>3EGDBB05<645NL@0ovphUhGe9 z^L%{r!yV62ZMf*@ifIOu7VT2naWL&UYXr}iEt^I95KXi3c6YP+D0nTv_I&QjD^&xopN@!Vkx=tS;;~gUpXLPLNqcBf?3MRj;xFe$@Rt;NT3`TQ7C8Z5Hd$DNgaT8KPFs`GttR107SQrV zu_nWMl+>Xlf6|d~C95&wtR>oErBP&dsUqtoLatcLV!T`3o89~H5Y6`P%TscR5ino; z`0>Yo`X;+S+ss!i`mno4SIZ!jb0$edi9GF4WF3glvE8ZF&+kv2Emu}c$jIo2q$*iL z*4%QLR1M~^3tKbM$p8%q@LwJ<^WENGEY~xO+x4xJ)v2XoaXQ5uFq`#*zsZI8)Lsn+ zmu{r^fZ%U5>!E}WH8LJ!u{Q=x(=}kUNLg8mC#=DceuDD8kUp7qV4rq+m0YwTPvpIZ zyoYR!r7s^WesMu7G{4J>uTB?UoXkHzrgV&1FmqlgFjSXF4IEajsv(w)NSnNTi}M-q zCCqKetse2|0AC)kyF>-B=l)Xc=~m!uvH1K>_I!0>DVw@ek8f33(kVB}aKIX4(3zYg z>|hGUR;kLNaVNdVn^v!7_hftbU|XY8&_&2==Z<-}>Dhwr#`@Cg)*|>D3tN*>S7Wv? zKa<~Hp9O-~mZp~GOC%)6d^*2d1^%X{f(o}(XdQ<9R(DFlqQezdnQbG{oYkDrPE?%P zWk$eifxb&*>J=IL6t>Y(RZqv@RS6wv9-YcAbSI3H^D#b-B}|f%h9BB->K>NMKyY<) zroOX~o1JXzEmaq%3bV!Pqb+{lIn8ng!{XjJTYL81i=$`9D9@R#srx^?IQ;aHcPbtz zM(>>8DbE&?Q{-rCschDbcbmq$O!98CzTe}LOfIBKYXv3?>VS^aN`?`jtwhvCnij(v zfv6J?Ht%5^Orw*!F2&z$F=-kdXKx(hup~Iz)1rxf#9$+G34BC}wXL z*^`@mQ{EhG1t0+5CJUzAL@xtez%_P@hDQf3?Z==AaExl*GI$&E3;qJ)tv&6u(zlOv zfu!%Yzkh3>6*n(Xjt$ZjFk{&QE^z`Q{DQyiAA!Ft@3adCuJ*RUf7^zs@oOQB@$Gd5 z{AKvt$pE@ppVW+nM0_S$3x^f>3&2qvOpVbMYLA#5zg@ot;^D;*H9x_ zRa#Fu6Dn(XTr)8ctvf?`gHqe!vX34eOh=Md^@Nn$$l{ZY+`-hvA3j?D=A!z1=j@N4 zo&V{J`m4kAZr)sVmhaDpwhF?eRW%i%r^(Qm4DL4a=X=(LqPC1Xzf?Hc)K5l*KFeU( z+TziY$U&OKh($9(m!(B5=C?5w9OM{dltE_OG(r-tu8>J-9*47VH&}ah;#v*&Q3{Xp{6@6Sw#3N65qPr$avH zCZfc$RR}#1UpnHK zIc5T`nV_ZQx~=ROw2%7dB9nU+L*72QTP|%DARTfS3l}C?RNLo~jQYksb0J=3^1Y=2 z6)}~=iXKXPu{~pHX4K1g7YP~&CizN6^B|%$l^Qt@-xjtuK-DqDph!r(c}Kq(+hO0R zYCxnJ66=~5bFLv-PxF%Y^0$|Q8*eW&e{g59#?lP>z^?H*DM%CNf-#6;_p zTZK}`E{{kvFl-dCo2)dAGEGw|`-w}!N^13M{9z-C<$$EUxSU(Mx6BEIN|D4)dFSOx zdb2upx{|q5A5U0`h9((|SDfq-OV&Q@7_&}J0PZYjaU2!;!x#l zt4EWYNmN&g#nobU6T&!CTFAnGEpV=Y-ewy|ZBC_}v6$8ER!vMOl3`<*rVOvb>6SU% zl0aA;i)i^BoO-lTXA50tFTa(3wJlj=?l|pQ@!sc2t#yM`4 z2lS*$Vsa)C_p)|@D0NFdM5{P)9KL!Q!!zb9F+|v-))f3~Ber|wmZc1#aG9su{{5M| zzkU7d|NJ+v{_w^0(Jbpo!J-%0Je>7}vtCX+j)>Jxgq==ecIs-43IJVOn<*?;bB&Tc zK4BzOM=w{J^tFZAwcWK)+=m0XT1gWgQk%-oH_B@pv-?LYI|ob6V&9;)Sn#BC&TPp; zEw9`%?2PHX%uNDHiGe1d0j*smvyIvd4#!;3+z1OaofM%`WoUNcTE00j)*{ghs4rJK z$DquflsQrL>0F!(+lJ)rR-a;Va~|?uUad8b*NdC=^7dSKDm9VzS$!t*W=ZDk^J=V% zIri=!{P=qB8B-JXVj38hx5|x#zYXDVW_J%WHVtA}$F)xR{)fA8{L)@o z8B+JC`a8$Fz2)eg=cjl}$OjM@#@d9PIC0f)gTACOVe&u=$_HNY>xlz}gjGWbjE2HX}Jdue`# z$)flE?ACklviAG7!~y;bG($YGT4A{2Um`o-Zhs%7qe<|+j;lRAZGBy>BoE){YPluo zB8UUI7;4WG20*DL`dLR4h|$ksve>977VPYAnyjQM1+}(ft43^A;hn~?-P%uvNP9Oa zVtQrAa36der`gr^D_4nM80+d(_H(e|n|TST&DlyZruLbB(SLJbn9$3sxUg=Fv|Smv zdA0u5Ex))inKbWBrHcq5Wk_ zek*rs6AW0ZL2=xqD0y;^Hv;z>gB7>y-U3@l`n9}vCF?w#vE7-Xah@S&SJu`Wb!cm8 zDxB1rAfZ*1NA%g$?MB%cj(X|vZLPS)Acj$Pkfm=Bk{sw-ERb1kpUYb7>04NleR|$Q z7ZP5$0iF1kh}h`iZoRmVXvCnk-$BKL(L5cQ`S>Jsu|f|rS8vhPov{+m-#OMXDC!&- zxW%vr;F$ej@8Az_lIP3g6>pnYCd}9*Ifs05BDzyeAI>VPG%IBK+^RmC6dplqs?euv z&dz3Il9D(6U=8Z3-=)FI0Sc-esa}K1o!|BwA+o=z>u!Kds zwK^s};oH$Gl+XmVB;p;#;F z5zn|ROzo7|GZUVB=fRTLVB#;oM0-DVaX-N+g9*7R0>_1O;p%#bvbcOg{w zQwaz7Vy0rdA9@P}gTEwS(X%i(+CEHHO2k59A+iA4GC4vbQCIgUg<`asbPg-}#toy~ zB*F212}uH7plY-BMbZrfUuNE3CjVRpbO62tL?b4XR0#ybf6XBi7nQPv1BZ*=+)Rw= zp2Q+VwPQrc;wRu6O*5zy9m5rVeJJOXCN+ zT8uJ+%tEHTG?}VKEG$CBtSqhIwo0cbf~zW*cZNfHk5}ams)I>$IAaba456sj zACM1vgqvR+>FPe)X8PhEzkc`+UkCTAhS?CE&TKlv+T4wdw&atgXa<)<|B2K9T;6so zxTo)~+lx`^K4VK25SbKloL7u}8UA9;8t`fmuI;P&+@nq1az;5HA1$~dhqKTA`WuYj zd~>ix`6u1sycdg+oo#osL}r#)99pizR3o?4z_mo{9E+Y@ec*d{Vaxv>isQoYT* zu(psXBvOS4;JYwi=I!cweQ|kedOpwPA)+K^Or&kTh|U|;oBaw{t=1z|x+OZVY*fQa zTGyDmM`jrgO#AKAK11C%W*2lxZ}~G;{ym;&JXfx;!5-8Z{ECUB$r4me#0|EPT51|X ztae3ovn$g?f*_Sws9o4!s@+-i7a~fR&geBL-OX)ijvu7UZoNJ~e0{NYZ!23a%q};Q zlj%r02KZLzr|QeI<+)O(-~oSa=25d|z^d&tsk*Jk!LVPRsRW|AiC_komDruKStDkx zM=dgo;Nwc$D3wp7e-AasPq#<_XlAa8yWB~~oey@R^AWK}a#M19$S{J#pI`70ZLML8 zI%4hOV4$Lxp{qyGcDd)m2$DfC5;X7u&uT_+j1G_*CzgqN`#T}OKrkpaJlxkW=%7du zLj@&z^rd!+`^l4J8~|uGC$n!$2J!u3aAG`);rX)V0q}(>!;!lvauxQxbNd&4EDUOd zY-Rzze8#q+HsF%@DexEA1$>)JMsHF0GVO{1H2BNkBJ(m+#sIH&7=U0nEcnZ(hGueL zVBrV}8vk=E8X z(y8;ANO(rKL1duwoy6e8VyRmz?4#>g(1DVCL(oFF^t(M*ug*U)Xwccl+s1d806UR-b4Df{kc+Ixw?UY;ZST&jr)g5ZafrKkAowO?^RQ zpT{PMO`5X{q13c@Ww-eJZ$2-dlr~;0z4+VLjgRlz7mKN#dT1szd1q$r#UaL(?7gLz z|NOhdKYeD{oQyx;nfl~z?BV)YEf~DFlzX{fe0>~xxMn|`F*J&jTyVf^!jwfRA<coSm5K`s~{t|5=BoEfFXE9{^i>K!4B#pW=PY!t7J)z>dp%=D|5AvLzE&-Xcgq#26V2)%*?AJ+in$YZQ;jfnV0(%F5tSsZqYv6G9sr;vxV?R{+Veh z!(?2PwM&cck%Y;+KFRn`nR7Ot@0%AguYs4vL)c&qbpxrCPK09OLiZZ3y(-g5uVcybf9qu*{!DkOYJ2g)_bSaZ} zCMXZ9Gbv0AWC(=%umD5Kgyo!a_zZl^STcMilsf@c1!pj$*e3I%Qk zK2tCFmjC`M3zm}~+k0tk(nrkwO7eEvAjR-s-p?hF_riY#WRj1yg1?vimv{14Krr}w z3Bj}@HQiYxb;$bou_vaIb~fJf0kJVtr|U{N^&T}9x}LNh{FNGp$yJ8)($HG0$JY+$ zfBgIJ8z&2asi4p%Liu67R^Fd>PX(Z~3m2;wKfGY*kl3iqUTjjtK+(K)I?4)9YAs*f zo62vOS%fEb#9a&0h2*UGWI?sqr(lEc-*Pzw@&d#@ zpBDV}c<^h<++I~EX)Vvk>zjq_EHy|;%7(1xWzuKF9zAMk! zm~LoO4ywlhU&7o>wXm4Jp`42%;2z@`_`<@kmRvHYihYgX+$7|e#eW*0P@chGRn~){ zBDOQ*+^J|A$FV~SdY*?M7Rd3t?g{?5Vb@_M~Sgvop! z$GD$-$bu_Z3x@Izy+;bwHAl6fipN)S@mQef5Nmp^A@$^1mOGVaC814l78L-sHm_VF z?Hm=gXmkP{rte8-W;PPcJB&WL-pv9|ClCz&mZo#X*~zKZXmVe|za@b>naq=DUA-IKSGMTb*CtUddK7b8E8|P7X`ibjE47u%*$X zmv?Ak2Bx8CL>()7*aGHENV+u@layuaeOg$s)+rIHdvRh@U@?y8UrMV{C%+mDS*mMg zECIvz5m`t%U>a%>w=-U0cfL^=m~R=3ap>UF$UuDn|v%W}hIS2}`|{h{3ggL$}Kb zCJHkOD(kD4E5?9tH{1HEksj#)7fVl&ZpbelFkqCdk7gwz&S4B!9W?k}LHFi^6X;>{ z+VNnc_cjL*A=f+Ce-2}Xx`My_8%)}SUxB~y-)pyi&ahQtQTB-YIY{vQ@o|ZCihhmc z`cNll2FAzup8;a{?`Z zcbP|ziec*`-9x?2=h=BfFxH0}=}x%Fy}vE&x(!Pe^$?@MxOUVaaTg1Cy8 zsBMS^NyFGpVQZ_Xy! z;C9DI`@0?Q*^|zti&bsPW>e8J`rXFxd)GPzVOe493#%~!QAtU4-OBO8U<#@L4FV(#6s3MWqe*M$g_kZ`% z@mCks`3to2Ik*>{s`<{)acQ<9QTvL)_La?I8uCus!WxD-ecH+5BC2kEXM;1cT!;JKP7z2lnM zz;Motstg1RJ>!YB?8fumtrvT-<&?YTpWUC%G?M@I|M}m3_}j11J*IXm0<(Zi7gjq9 zj=Qwd?^XaZ@E6f|oFVMn9bN=98O@u@5rk-oT%b^K0Bw$L`{jKyry@O{HHFRC|Axk! z3NyDFTvbrrCXH3_pcCB~HjVj{79@bUiN9k_rJAFD)BMajiGuoX0k8{Y);PwAU?NNg zGqX4E%Ol&yZE#z}Mk#A1ey!Ol1A@85U3`4^tH1i<`#=8xSg6t#T;J-H*;;Usw5d&) ze|z7gy=!*s3g?HUs?zw zjpXs?_cvc1?0s?n=!YkVUtP>TT-$hYIDOoh*`MEi{Qoocp0RP}d74;HCuQbTMOKlO zbIv*EoO3RwV$PW&DT~T%9d~e?}ZMrd{}qfVse5w_Aw|Sd2fq!aCf~LnT+L5s8ob?Fp?V zC{Nejkx}2#7q?E{otCz1&hb$7a0(G;NEXFeqJFqA|Mb@I*~-S3=TK*%Mli8HqKsQe zx~9$n1}pG3WE3vj6)>&0ipc1T0f7UXFm}PHkHHogud?;ueP&%NM~`Qv<6*~IW%27f z@%_o_y|thI{&%(2Dl$K%M!v=-MH~k*H<&US+GAZ2hcDrQ7E9;S1@mD;&;mI$GLr}R z6qqid@NUdaOEuE^IF5AYawRn}S;aNdC{~6uBNO?F`C5}ANL#`MM{yz+E;>af7ERVK z#t>iiIC4;aL+#fpR8y=WRj}grj|MX9B}rH&aB>076ix?UNaV1)WRgLTOOc<97p4;a ztW}_+fq#ZTOKC%62xE4ovAnY|xiMvq*}bK(+@pmm5{Cp-OSf}+u`vmarxHk&m(%cl zx%>uXhBW3TH}|)8kN0L*=jv0nwY^n9Fhp@`*mXHw0%nJh-7es?%OnJ&i4iV)Y%zVT z8gM4e5PeZ`)NGPAWV)!I$Y_Twfg_{#Gw=-WAhCL={C+TFAgC!C3f088%DRC=uhc06 zYXtB7m7#WmjHXXI`4%Z%!2%rw5e07VP%z?*+RU!uVKD6JqIIKW@IpRBXEz67u+XsQ zU=RibV+6b2a|QiJI1T|^09Xi`Lxv>a5(o&mys+C~CdEn=0Eb;ChHKz2Mn8zFk+q0{ zcR(=I#Uykf!EdOOfEF_u6QKV|=Oxgy_zW;QT_7(o7ttRVoxfPo0_Cy!g(VppW&~(p z1a8K9^t3?x1pLKlj2Ri*Ug)ndtzU2Z1k*G_BOs&cey|TEq@a#@2IY`Ogf0V2!Qifu zQUz658>Meh%IV_|-9SX1R+tzm3<&6mx9VfU3QYt4n!}C(n5~d!;4B6OWc8{ z2kfGnm?gJ4iUt-)V)%{P7{EuoK3eorTj{u!zGKIE~D#*i15JixN;^dEyp-<7wUjpMNRcG zJVbo23439pgww`u#yI!s1n5nGm=m`P#QAor*#KXrPY2HtR8M#W_~JcR={kz^Gji{rY4L~=D}aEMi)AjQT!y*{olhrF{zsAQF6Vbk7d_M6k# ztG)cQn}a?%(;-Iq;RhYR0tIbI*x+Vril`AKRPsYE&TRy&x5xAcV@TdmY?Xv_anRAG zlWFb#m}IJ48KncGvN(B9O1v56Q^SmT$K7ITfghNIx{mAx{%2=g!Q8+i7@$qN(~ zBalHWkSI7nVR(TNz>B9J+&x;aCO=)U#H<8P-vGb=f?fu;V$|g*XyBg#yMS_BfMCFJ z6Mxw~7as;9nuUZV(I7+IMBWR&8edmw71CAA4n`NG%jtybAeSNZgzGBYW*j64^y}(BZqyec&62>5mQ-s(h;dqqr{F=)FLA3z(Gjl>nC7ta z1?)C;i~;?H1R9UJoHuqdH}m!sLdv6GzI^zvzc1ZgG0$gD|N7nE{-?jsOsApO#nw`+ zg)WW)LAb;y)H=23CRn(+fH%P7A(ROeGz3nudQxmwpeBza6-~^~C=E)TS(PeAfWPC7 z@<^jpAIpzUlxCJkrxu6PrEq#U05UlU+i%fn4l2b)rpUm+7;8uybrCg1)T=aejBW`= zU~|&oMYm=nV9pp=szCzfDu>%crQAS}qgl^&r_HgNFJ6U>nbTB9o7v8o4!h&y^WFXP z9pJA$<@Q&ikj*1%qnW^_VS$*EcvMoiQti{?NsALB7E&^u+!1hM_-!nV19|5+=IYbc zWI68hDiKC4;&uan1sD|gU0N;G=@C^H@*aebX7Oth;i-rfA(>C?7-|9Kg%u1Jah*zf zQ^vsU0}F%~f+OupPv2ZIG{ox4Po1bF-9^o z;0eGD2nG=itrS>j0MG^gHZ_p%^NleWf_Cl~QGvfV20QSG0wC0#1Ddf52L9p#{|r36 z7<-!*U`*Bsne6ZU;L-;lBJz0&Ua!Jlg#R7@{R+y3`hI`!^bKrOe)1tQ;9=|73gN@s=iIA?xUdlo|HSAsHC*cD8~6DK8OA zGv%+!1vzXa>-K;Sh zKW-Fml_GP&?3CXX5GHf_a)>E24V?r)k)uP zSPvGQrziD|I}6#hdTOPVTgmLayI((DhNcDLtMc8o)gK;H(-v;k$4J`;qek&?Bz3mR ztp@0MmtZ(d2TK-puwzb^&opF|A-xI#8u+ny%h&`l`x>nu;wv-{q9IX{a>7YLvj{(8 z^`bLEfIeTVR9g(X(X5noqIB8t2M@S&)w+gTQ5$s%fiK^dc7cM1p5*i1ZMV` zg^+y1=mc7iDuCyWz~oV};_2?VicSwCwu;0|4JKihHEy#1OXc|`51 zcy^!dF6@pwGv>lv)|@or$p+yKhERrx41Z#iBIXPr`v{qSDx*ZC%%fWjQei{Te|icKz25hCjqwTHDcNo1hke)5XYg#2RFa|o8S0Gg_ZKu?)1X$Om#9h zw>rLcyfn8nk)O$;JtsGvsm$gYOO?V%6!?oEM{wqWvJd!+K`B!30DpnD9*+uwD@?&y z0Rw+=frWNN^{$jTG7<>ZeSx~$Uv-+o3QJfXELbyR0ee(yjHnGU9e$^W-#=8BU5;6( z6sppM1=SMTw1e+e;g~^nNGN6=PJ=wJ0`Fltq*w$4f>Bpt9*JXnVjE3bYEh0)+qAU1 zRY)MwOh(p!eNR>Q7LR7OzrBm*N=e-l*c<)&&)-3RMOO@=EFSoaAWDT<>`6LT5u|*w zJ-a;*%yq`y=qW&!vNdc+ghjNP3S^@Sqi%9xHlB;C^s?c}QZf}t<-(alv`|UZ8in!M zN*U!)8Be(p^ThPYvZpc;_a%%FEMe!XvT)@wHFy}Rl!zHtZx>*ttMrJWj+XnNw}G#- zgTiX#Awr7R3*8zHGvTtkv0hz0m<9yHh$J>JY+>ZpQfC&?oiR4DP|Hr{@-syh`YEvT z=J#WR!!-*iD*AwQP-qo-@*c5GOjS^=UK_4xHkK?U7B=Ts_mEOOHnBABaY*$_nnFla z35g(|`P>ePykBExpf5>m7YNL}rcFRb?xG^7AJ6SRyk0Q0LfC*4CZ6O%EgMnlA{`5c zIFxg-9ej>k(61)b3=Fg+Fcfr_QKXC7dLYFV%}A3T z9O^-WUu)CId<7>Be0NxLGo)~0bY3Q2L1Hb>CK)g?L0y6kgIFE615R(KJA$Sa`lE&52q9Y+o-kMs=p8s^V`C@r|Cwu5yk7RCd7uYS;Dp_PZ7!?WQ? zO6_rS7n8C#xAPBoV$Yu~tle31HIkm0jJ4*@?o5YPhHVoWR0YkyKA(DZ(&tmzmaF#V zx?(iJ$$2bGwSlm)-K{V#Rr^AEcHCtg$qK^`NyyGLDG(h=GsUf=uW zThDUMwO9f3+@og6<2KyBnmQ=BjYboW`BMGq=J4zNg+INByxblf^<*Ef@iV3lDG@_7 zJV#CQyI{bE{=113)^o^T5=NoEW_G&;NS?IcnRUP1vcBG??3J0jW!`>`ybv2`_}KGt z=46mka|))y-A-wXn%N>6x(>RDO`>v#NK^s@41~U}p3YX<0D(>>;24PB%>^|N;eR~?2 zNlFvCPBobyQiLXBkA8ZBdE|#*zMR}1Rd}ReQIswzTaKh(A##vJ8a@u;bioi0IY!Ysx_Nvw{^Gjf*ht}Z>; z5c?G%nb}C%@F_WFZl8#NOXig$tdeKt52+|bNk7h72=|7N4;CIAht{9my7}x-6*1{b zt_MHAy7w2)W3w4l5PHg9q-5mhau7em7=oo9`0Y^6wQ#c7jPyL39yy-*@^8NT@?U;^ z@ba)YlTB5^Aemr%Uf~=YOdG_@{y%tBUNCeC9wbvscaFAHmK63 zP51ul)%rK*)6e!@(-}O+6d?m*t{El)>VPrk19|B-As`sIOiw4q&`-dn5pA> z55Bd5S|_Gm5@S5%F0OYrGOE&6T6W zakN#M@x7Zxu#;;-dZw1eHS(lxg*E3gr0oKfH5*lCk11VA)h4U!`>Pwb*Cv+6;>AeF zqXhoSdA&&9!2Bx}_u1W|c+L!(2qj`tmjn=u5g5ZSPMb=rSZ&i_T?@q&kwrin0~$Ai z1$VBIKy<)mTI-OJF=SzWM7=a19{~PhfI?j(^jAzYVptIC!$N^FvN%xR**x67U*&)u zLg};Gp@1U*qD0h$@sUYpQp3cGk+z%Ai7o07olN8sz-G&w3gn+-7eJTLy8GLD``el_ zX~>VE)WRd7qY0fzeWa7{Rd7f^DLG9{g(DacjQRS5)?cA_9;?z`9=VT80tB~Fx}b>0 zBb+hM=ypuwO7g}ikN_1*m&6*F~I#(W;a$Rh+If6 z)a7AY8<%vA(RZ2B+XF(zr{md`WEBV6;|?bAQr``HJVK1GQV8I#`#EGpXTUu5Ve79D z%ZxiJ0u^sC`#KqLL6XqVP83q0SVqM0r-SWi`^7l~L1bX$uq=je1t%rfu-{sCkqmTs z$`D-0gjWjwrL54Spc%PW=xuGhUXEQ1Yb3+Wry4lXv5-2ZF<0%S{c2%5w{&Oh;p_Fu zS^wg4IyUS?$kp7lt;L6{<2&`K+ru}XuQraW*$Jo9L7ScSZ*Jw1d5yzKcUp#0X=OSh z_8G|`7iVlLFtHGirqnhQbv!Km@~rm!ymEB6aq#+R>GQMX&a{6qhkiigNIbAIjP6?V zbPjRQl&H}-S3n(-Y&a$;1-N;yWH=_SM`>BtB_j{wD|H#uhZa4*z+bc-$wLm2*WAme zckyWW`FF?|-4Gqwq_}CI$rSYmDDdS35HDctQnOoSv=%8908Mcza5F*po-*xnjwB|J z*BZB%^eI;pf2VUa6CW!ucyf0*ijgoDzF61V;Iyp=!ItxL4n{zSkSk?5 z2&Zu37AzPQ>p}^6SxDB!@GA-#l`$J`R)FK|{(SauF?2G0>tBC8_WhmcXY1mHWOHSMiN_hS6j=C!67sq z(D2Ov@ajkKtq(dxmf?`Ek;tx;S08UzK_EB6)#I7j^To>c@XKG`-2LI<+1Gb4uMSd+Ie_od=X?5LZ(_ZC>+K0Xa_?;EKm8y7-Rs{zTRB}s3I~L**u%<=0{Arm z!AQwNt_b|RP=-JY4N)|}7qLDDHggV zSlwb2#iCZ?mP*V#ftpSh5h0C6ewWmN$b%t(FU!aVpA4cSwp=yWLfDubzk6`_=I-Ga z=kR%jmJ8cop41Pfu?U6)OBGb3bulp(`{EC;kiZFw8wpe{Y&Gk_(c`(f7kj0>vE@e_ zh|aDpSEkoTw)YoG<#4eWLmlc^uMbeB2UJeY{XnSyE|=( zmOQAg1M>{D)#*5R!|PS!0{&XDa-kt%m^y%}S&=F5#o z5U8b$>-K(qKe{*8u4lncRa_rM*a&C`G$u>^TJS|6)d9h{x@2Uso`bMWJc032>NfDY zb(|hO7opI|Q$+=^G3U!J4M(=?NG?S-8t5z#ZliaWFak$!H}Ipw_YT@0_>28-x*A0S zHayo&sg>Vki8%qmTDKk%(8#H9MxB9Tc>mGy)cU-}Y6AX_&5Q|UT(m_ev!VIriLG0! z(@SGhi=!y2K%a79G?lOV3^u;e!iyylxv4>@BRoDbDT!j|NP==uF^-TL`0EHL4PGfk zR$LW{uOiVn9YYv^Se*=Rw=<-}F9`S>t$J}d(R-!fpN&2l=3l*2lt_DW)fl=P#y1-7 zoEMRdE@WNWWWZdyngLM_O0}FNA1cWTI6lE&KUG`WUPPjZFYcXOZmjGs&2P>WMzaPL zUBc}ZvpNC6Vs58c+-J7){0Xf+Z`Ve(_KZ#GkvGX1n*`+=fMB^vF^EQTdLNXxfL9E~ z-SpNTW-DxZP)^!vUW%19Xrw6u3KS(!gk-)=PSf(xD$>I4>qp6>mXG)@K@@P!~cs>4vh>wy*E%g zj|)>U@E2NW;3gm#c~B6OAom8eHgKnt3NO&r%e_}V?!NS^zN;NfLKnLqj|3hW>tNWC zpvVGt1AH&^&shHAjSCe1pzTsO@~BlpR4QWxh6D?oGw>JdU|=y~teRx?`|^dR1*!E4 zh+mkR89I?RXoax3o!mn~?-HM;D#he!KV~r$Oxz%MW6w*Ga=I7;xC!GzVXijgRYo1? z1sG8C&`yh)C@__mN30Z`pg9-w20!U{gFPnQtwz!OWu!Ng-pi=SE%<@M_NWXhp@c#GkUD44R$R8}7(ZjY zVW0>DYJp#c7gxWQfmazG@yF8kcx}6$UdeiW&Qiq?@Gzq>Nz}&;n1}Ll<;He# zeXmw5TOB6qOkVTkApg~?xy{4Mf222Ws7rBh)3KAfmsrJBzq)|8l*0Z%c(A^67Np^{w#3W#))yAlVg?hVJgx z(#=r_ceQatYA##e9PU&NDu;bDUmdT$I~{wxvHkTqlCpmNU;p8!|M2tCSLdJo;brk= zonmIRiMkHn9-n=4{@L%J-THiQ{&cQ#IC1uu&k*-L{d5zZbg&>HM~EXCLYOV`^pNL+ z2ugUU8H`>g%1D`gA|*?z=fBTe>+5Cp;8ugW9HT>tS~~odSjD~&CqQR~=QDmL%_uGT z5Kl#e9T+1ppcaqKi%W!R3p^VGvS%d<+=n3j;$Z~#Yrqpih=@}?T9yP_z7#imhZgsI zYtU-(nUK^WLWY0V@0~8X=PO*Nl%i+T^lZ3dvDYikRnt?&%Idg1?K8(+iShi)-+guP z{CsS4X72W?BjZPwGEBiMkM}SU?>s+Rf3RaoIkL0GogW^b|NbQgB74djDtbnjE7+LN z+?xF1Pj4T*IIwvY(YSeJEHSfCE{!G;sey_gu%Pe_1+&J~h_|+qg@QGpQbNzf(f>DZ%`Z zZ6bn(i7A+@WntcDg_K=7DmuTAVFFuLpNWYlEzEJgahQT-#pUAT?;c=OU%$7C(^_yM zie#r?1;|dvaEHT~+9id{2A4LVhuqGZup@;GedRKT+L`vj*Hf9QATT*MoPjhtRfsOH z&$!%1*X60e5m_hyGzYlZoIeKG+hv%w{X^THd|xjZrnzgHt3faXet zoo`Ir{42NA8&ufSI&D@5U$ET5VG4Vh{BAm{ohv4Qod#)3uFv1ZTaF_q;{C# zoYK)<7Uk;l#M;h+KNoP9!YDyTA)~z%ijK!%{Gn->GMC(2@WV=W@bvij`Pu&G` zB#l90v`B}bNMRF5j4td1anxifDTbg1F=&yoD0U)XW{}U1`qw@|FW1BwP}0E~^$7Wo!hk7U?DZoi*AJhDhU^m7y3_B zfI))QPHuy1c#t&!p;1?FOFy|Aq$^auWI6%oXY7(7>Hx4}O^i%wbm}42<0`qml})_C z?Z3h5?UhoI?ue8jya%?Lk6J#aArF%VrB_QA(kI$JZEyXgr~6t*=an8}GiMT-E@Vw3 zvmF~)Kr{BjSopSgw_Uq_xeGlD?N_jMMOH18!>t3?aYwx&ruG}8OoRG*Zx^yeq+wgT ziH}x6><|fJD*peN%~8396Ml2+;crH@%QCJT$Xn3!C{`I!Nae`6$o~geqbvXwduZOl zF#u*ImR4eoc`=VeIE_%O9wGgM?rRLAJUUh56#Rmu3!6%L%#K!_HY0Dyt43Z87*tu% zh>CXLFE;P(Lmgs=5>dk(k64*B#1^vNMg$iEi||K5K&~v=g(-c%nJJ8@)JX#(1i5y; z&?!u=jvjpTVDZsLWuvfmSi60@aA!C1`Z&M27TDV_k1u7`&z5dJhI;w&5C81(yWj3T z{A^-t#lJjZI=PkJ+DxW1nt+w>QP9T%yhc=r2Hm-u=GD{5)8k69thc&YJ5|%;_4Kz- zR(|u{*}I<}Za+m*Um3ZSn}7IX`8UtqJ5!d`QQd5n9I}WqLDyuRI}+E5yaFiuZ4z97U7X~V;|X-r8)}h2Ba0u`Wl{@l1=nd^5O&%pv#f{-X}6B7?-~+Q zWOR6lKs(btiXJf;nN<3y8F8=BFY&T=FwzTO-HGl_ApECtwu1a0l3fI8G%=u2kHq}* zW#?E5hXI_y921#-hm1rS!1hFDQ;+Q}E_{ASPMeH}qy3XUG%JZKK5oL?D{DHnyJ#)# zxL3q9{@oGhavtSGur(R#&4`aSy8yN<-C`+lxIF6u1#q$c>jPl3L`UqCP};4DKl2>c}p25>di2((Ttg;Cm$*hU2A z<8N_*$08W6B0OHu&KQ0nhwh`d5t$u$1DjmnFAS2+Wtnh*A{iXS0bfl+1{Y$V^{0Vze*tS7DNBTsmYiS^Z{&A}X93Yc8P9c;O9Sf3jySdZ{{Ae!jeZZ+moeDn5}1 zxu*@8r7m@3B=zo>@2B<_(5JvbKViy^5Mbv>Z0p6*@`IZbw-;``I3C-c+<$%)-X2Zg z9EYn8gm$LFu z#amr1N5{e_T*e6mn+TO#2Kdl=6lwKL0lQNv zAmBabuttH6n@{0_T+Pf)jQAYG(2?_@&VsQ>C?_%49a1$VkTOHQH8z)wxz3En4az1Z4Ahb)6eE}21AuAYN8U+=rd~ha(!)ecKHorVFzB32K6iv?L zDA{O#sK)#rH(XoqB z7gIS<_>(Ii!3}if#%1J8wzpoo(eiQkKr1%RP>5moA&Q||GWbCc$Y(61XabL3T7vpB zD2Ut11|g(q=(5Me`ce1CY#mqV(SWX@`84pv>PHfx*-9^57-|9GedjDqCsBu;rc?kC z&}_4ktmFf5KP0xbvdI#^6)R4J67vF9dD7SEQg(u8NV-Hp6UC?fKteJ!Qkqf#cmXa5 zUlFVDX7UNO3kOTSQ#oYgX!2G?+K3HZZo8h@tkRr(5Yg_L1V5%B+c@#XTxO*>pcx{{ z2hiwR+!}*dV&Z6eYQMg9RNcLqJXsGt+e;kpr_RoY=hxDE_ZCl|Z-4f7@9~TI`wxd7 zKOQ}~89P|^Jvu7x?q&)_W6&dZYnb)0pdR6mB?X5ofv2aHquuOi&1|<(jwjq-pN_wK zwD9Qe?AfE`n~&EP9<5=7jUvoDwCEUq_}N@&}+C8-BQDo6a=DuUt|J7`(KD z6}J?RmeV`a2%YxNmSQU-Xp`yd?F8Y|+Sj7;8DSJcbcS)auGp=>SylC;%6k>IASoi4F_GBFe}Af)<=T|~iVb26nU1+c0^h*<}% z=i`n~5z`8mMyTfVE@wqJ0q4CZREd?VFU(Xnj5-ml?$&U|z{SSY6@3&9ao^1X6 zAAY|1%Zq3K@Vm%%tpb@{-hmcx#7se`4CKYlq(i$;f(VLOs$=fB=)(i}rRbh%e;Lz+a5Oc*HvR!V!FdzZjFTN``6+)ukjb(g+XK zF|k$y_!=Tcl~;w$GGr>iU$Ft{3T))X3AI9GA&QMsj!r1`86bKu?9O>dqWRUjK5a+x zHmZU!@1Qym-AsIkgsh?wq-0ChdF%6|lec%r_oiKCzp3Cwn3yD>4K`BP2$$E#5JiaW zl%=<4zNO;$`HD2CLMAo>IrpFMA+7|Q%3?i`Ok2|_+jt{cABmNQqpQ19wUK1Hbp zsr~WQHwSlr^JIK?JWz5YpNFLyGKJLTrII`6gw72~EY_IOm9|0NiBxcV(qRZ0;SK{+ zige{jHGxI2z$n40v@%hgSR92y&umwtGZ)}%v#FFielXz#1m}k1#jzBq``OL0+I*ol z8HK^w8Bv9E7JEQuw6NvkKBQYnG*p3>4%0URw_R?v%^`88^udNdF&yxuOnl|w0QDM1 zV2eu}$=M@CXRhi>6>Sc`#GlaBr()HK2&QSw)NZG4cr*uNFT_YBIRi&@RRqNcex5~$ z92HP2wxnb6aJe#HuPu&b8u>x#AZ*&}C#%Mw-WoQ}ZB6Xm*+ku>-6l+h^?Kt8p5Hhz_&Y zX_uxDpc^HZkorg^pbiObj8c~|Fr1?sWTtG`kPbpw#Bk{mgxI0x6D*2BuYnn{cU$DZ zUryMfPB^hj{!~1OC8=kn4%yO2oZdF^Ad;`H6Ru(Z3#%7f$M;sE>Z}#HzIa5geg^{C zd@^?9wLbAY)nC9w;afow`~Y-5c9{u(WyBSldn=@1=rhe@pozj`c%MIPSK$$ z6g3NcTZA-@Nyc-)@+YIiYUEb+*un)g~~3+}aHMJoA~u!e3Ekh=M#i`W?i-5~J>NyzBkcwfogN9b!o zR10wk@dE7FNGjY&cSr{zwB|_3Y!wx0MR=az4m@CHQ>|Qvm8S`7aluow`|@D@=?+wU zNQ&--N7Bf?`{v~I+q;kd`0D$A{Nvky`vcrbw_eml!WA4Tu7k@1miA*cVbP9>tfZ5 zZ7<%yY8V&5y}2NMPc(t12L6(T5T%eIuR`(z9$8uj0)^1030@8{$jHKiM3b#xfuTb0 z65k+V8-%#8USs#6MuF#&v0YL=oS0S-H1If**$M$?A&3AgASv#9i}%*<{qPvURu6yk z+4l2W=$l)6yf?f%jR;4Khna=S%<)QWDyJC@XZNQX_tr5~h9?uX^?GAxZ0U4iVW~7T zmm97I!hTI-Bvz}3QU5x%TutQMzPKrpw?>O*M_dssfQ9x!4rIuh!y^G#!T@SI7B!?} z#u{QyBYLxzb%2vjb6s3mB*8IBdKyXKl24LP?f z@5Bn&nX#i7D^&KGBYN0v+-Qt4i(onnmm=X>;4|9- z7Kc-Bv%})V^Hgk;H%A;X9Yk4NX}>@=AXZagGLjgXzOcd*lnG^hLU}(Z=vdy085uE^ z@wgjypNxGo%#uts7Q7I{>r zlmq@dXew~51^zbqX90z-V8d~P*b2l|QTS968%Ypth>>hVG9{gOeXs@jKj;_3x)Y-u z3bmzLk-{MDCN+&n&9Gu5T5(9Idw>ZGZJ|&OL*5MT!kO|8pa4`S5P5Wn+=piz;M*!0 zx+)~!5DtQ{Mdj|GjP)_8^#+o4hq{o8+0ldE!>bqyZggI@1{@N-oG0URr95ne0l}Dm zn~j0(h}~$z$k5t$>C&|i+Ip`-!-;6AA-B>tlJ?ZIANO^3F(@31s$EKFg$x4~e@jS9 zh#0$EvL3tSB7q<4LS)4Nk^PHR(|B5vcAIK3f`WZ{s0#-VR45{2^HN{y6>|4AI#HYO zNy83(JuOIh+H}Gza#pKO*ke}_eTG)EwAZbs`}ByT=~c3Z{5pt)F}{flUR5c8FY!U| z6;HrBglhOQ2 z;oytg6T9_=qp`RUX!hXg((>^b)U%U!msZ{!O?`2QHLG&5D4EGnieBi5pnq<+NmQc= zcG?LoR{CU>lCX(lF2psXsMi?tBJhMDWN>X7QNRjs7sDha8AUX&R+RH9>k*(5^u{2W zF#?M+E*ca~I!=p{4!}k2+6|}V27DHIH+X5V&^up0D%_fbL>ZPkaBk>`!BmT9HPSeJ zmC(fQ4Dz_D54Qpv!%$?cyt}*i``TI*G+OWe^6uUs*lc%t#Wu(cDVSIubSx`^lVc6qzwhY_?b0Z{^@>lM>q{ z1Z?_nkCnu9j^Tj7D}yB#^cN2Bwz%p0KmYpty9c?A8dNt+kGKB(KmKhq40$2$SjjMb z5_BcUXB4@sr(hlV_hErVdM}U7G!0VUN0lpd+ zP#EJd74VI04Iye={t0k_xwweTE&>CCa3^SLU^Mt=C`f_7n16x(Xd>2l6%hZRDV3vP z;S!ofINM_)FnIMSf5+qnvFMPBjo@5G$OQHSje&}!MHn|ih>l1obSt>3Q4}-Ho-e=n zfps**R%~V~!m_lo%Sv)+OTM$he zU?2*W9hmQYK?VL{JgBM{T~WWnWfA(FGP_yea!Roj#{BD#=xyM5O&qUV9C8cXW~$3d z353OgjLr~}D*SwRR%eR<*)8R@!rOoM{o}v=Rx$32Z`L-xzn?yz*G)vYh%FrsHtsB^ z_8T}lmX8-5lPO)fx!^|jrVfra>5#tW#q$AYvn~mdWPq%ZP4S4!Cv%Fauw_08&HV1G z+k20;oG@*Lv=DDY2M+!uQ1wFvjS*NM(xL|t+1kJPr{~M%bcK$qvxrx=CTpYdVl|X5xMvniOY6hgnn$b|)H-$qBJLNfSz5Qj7I69eZi_{MnC0|z1kPwWG{b^!xt<|X4N0{$om-5|$yC~y z&X{D%0gj-{VB@B19%O1^E)K<9rLo+~!D@A73<6_-Z)UdQ$Oj-)bLPExj1DJD^R?nk z6_?g$gxWbE+$&FH=9>^S=Ho@w^y9fT6Eg|*O+xjRsu2HYceF{s?&b0FE74Ovf67Uzz zWoRBpf+#|~qq7BU3OWV-urWeY2PYBSM%V>I^oR?qD0~SJU${Bo7SXI}Kzard`NQ2P zi*JTy$*3?t+7foQiqkRJj?^ri2e7?r>xUt?6E_gpco{MlVnSJJF09a9JkqDc8yJC+ za|I6$Rl}2oEd(vEN68@Sk$Ng_mDAf445nAh_ZnyhG2~A?G~L5X+uw>$i^=zL+b5S= zKSrh&F4&roKl#b^Phd>Ob?MqC*E?HUu>!tv>3Zv@S8jZGwewR%hyZ_C0bS!@P2shC z*x9NHd3CukJ7UEcawV#7i5W>*=XJZNKd8kn4>7-zYO_PLxHmWXV22$rP@T%~Oj+d7 ze?mgGWG{r)kZ+;2;VP-?6SNfzn(`qGcYQ`F$)TYIEf{|LU0O*g>R+Ggbt*N5&^0!J z=~5%KUosxYT|Krtjm014YlLr0ta21#fVvl&BuHzanRpyfXIiAL5Lq@6j`xFTmrh!v zv$5P-zPeM3OodYm$^2?g5s{DV4S)Nmr}tj0KYY6I^ufe~{p{nN*wd}x7rWv6w?a=2 zlMnV{k8h{WR=np+uFrQOzqwm{dzAd?2Yv7caMZ45e%mYQ3p8s z7Ao_fpMW%OC$|t3)T?SLQsvbp++oe#JOcb&s5t;WPJeki`_=i(+q2rUy};oNN_dB# z>>T{no7L|gLXKr!E_vP;!9);V9kXHpS52mKPj<)OoXK(?s)~&TJq zjPWtyDhNz?OR;OaCM5Pj_a#DfJXc{CxyB=+s>?PNH#EYss@pJ?Ku{I_SLivqs-azG zbR!-C5-(hc#0PE8wn{l>$slhKO_b12HeY4$`@--Bn4jxcKcLaj*>Uwc;mVMl0@DQ4 zcN6DJSeOz;1UP7DdieoO1-ER+GAMd|9oIP3i@}Ixc)?CuG9#WjhXb5&5u7X10_8|Wm%PipU5TghBD=MQ0 z$U8XL4*nSt<$%s;DTEjbbljsOo(3*@unkRxauplRFBqK3fMYPy7@V;|7NHCKpVB!n z?KTHqRxfTZkWV*PzzELb69@Q2@ZL=b)-m9xqezHg*I}-NQv(-GMTgKAh;IrR>+54+ z05G?jGOqAga_ZJxWovxv&8Y<|wv+`mQYf8=?icfKZhiR9kDr}=|HLyEQzb3-S}?v) ztlyf}#Vm-e1_a9jy4uaj>~bx;I$YnIQRN)H`07Emx#|U2L(+Wz%?Xsr4g=F|=7b$0 zyN*=^1w9s@oXZ1$V`-ZUQi7_>>E`P7WQUD`Lu||^Pa*s%qPAE#b|cGaWSP|zfUi~0 z@YuuwSg9;R;BP3bhyJRWFzi!mEL?|^?=ez?dQ#NE2nR*!QJ1fVZ@~Z{HrZLw+$JW1 ziM3p0t7u<{t-ZYc@Xueb{cvAD9>P3}F&_iFZ6a#N>hjJS^jC`3>iFVK)mdDF>vj>GoLuz@ygxl^0&ux{33kh#L9*RW#UaKdh zFU&+IcgM8eX4?_8%~%{`!Uf2}mSxt{q7jwN&XuXiBE>)`YmSy&=wcX|Do-wt&+RP^ zuTLaqO8-QLM6AilY-M@W6nCH?sW@BPIJ-HqG3!eC-9cL{6Lf~GSXH}XmcnGJzF3IY z{Xlc94I znyd!~5gNhk8xZutItSqya$Ou1@AAV<#I<3_Ld1{*Kdy`mVO+Y12?8pGLyp*0EPo;6 z#0v!Hd~9sd|BmtnENbBuY6fAk2!Jz?-c8HQ`>-r16;tDBlw#AQbf}sYCK+4IXsSmB z5xPhKca1QOK?$9%Vs|ilNKzUZL0c+r8?_s$jA$Yl((w8eObB0bFKU%hahv5O>}^_3 zhlV2vTQQ=V>Tw{~hy6D`X#Ehqz|Crd_D|7=`$^knbpC>WMn3}d)$j%5LgL3qS3kMZ zdKJl6-F>Z4uzYkK0Uf`ByS9}-fPh6%=pS6a%yU_aCtK8{qbI28NLhQ+Hfq)-9mb)# zz|Y#Ts$;|q7))H_X%Jk$BDc1%iP4F|`0i3C>|G2JOUgw|Rx7#ZqpoX0i<)Cpv@x2c zv@p?-^%7({b*uO{Bn(NyQ#;<0*J9>+5{axt9p5@rlujg(3I(9Ypcmh4V9QLE!M_Y? z4aOM~eo8I$_HJHZuYlOW?k0*!{Sq=Rg-*R6Amq!mdwq|W+6s8`MH!*3rla<>-X+ijIlLq_~_dQeYx%KIErumq4OBao^C zX7&tV!pR945UT|V7MNjK!G{tP$4tRKSNvEyNS9NkK`kSqwN9sWC6790B5N4tiXZhZ zzTJjnqdxiNsbQ&z!nO2+^@(@qy2&JRv8G-fHC`PW7V^Zf=At&jSdHNS&>u6Z7mD7S z6MaU03#|+4g?3s;E4dAfkj}0$yR^s`ZRx*pm2eFj;2T4&oeZRtwev-TFz-0W!j|P6 z>i--wN$q&ZIGZ-iWq5ffLbp&vg+mwo#h>8g6%4jb#xw}=q8N}+ac~9r;)RS*R%3sGrESw{=!2bVucj3#IH=Fn`26_Plh1f;sh!s*R=et)8LXYuftFYf&O z61ystHPlY#J&ZZaI>sxB?PeK*sP3Bn9|h;4i=zeWqwzz`|Eym1;a{iA4-pgp3M1-{$;_{!HhY@-AypY_r8Agpa1XwdH3aUW^2?rpUa&s4?o)GM$N!qP1q8d zD`(cm4!?O)-kGsf!kCLoH>acX75wPX>jxBu7~t>z^MCy8=eOQQ3In4l=fc4TRJJ^> z$Eps3*pr9bqmwD8o*uAp!Zv~5#7PD;W5eN@`TWds1*L(0pR!VRy6wQ(p@4;9my?1z zW(57i2;xG5nqttUp*eMoR7C4_3NinB?Gosp!9PQn1yOV=@4^TSpOMYU58K%hJt<|Q zM?!++xH~c*PL6p}C5y|>4n`H|DU-$(>WZ~?JmH&&Niyc>?x<%jja*r|M`kOzS3lqP zE|o{`ZGZtlp4+Xr_eS>T6cHnOksw82c_dU58~I?!yH2fD&5I9cQc#(B zTAR=pHLPuqqeW4nqRAB$I-?yC%_<$+Y!#(54v5eYCsoKgRcDr0jcsN;T9{2WwyK$m7gbGgAt}}L=3(sjFE(Ev&EDT^oNn#C zewbTn!2AM0fg*^d;1U^VH)xiyHwFJZB2!2L@}l;)Z{P|DG29d21x9OOXe12Fo2BSN z2ph-L+(bimg$;|^Cd2HE!zz}@xS!zj;Al#PT$$dB1bD1~n?=AV&Snv?z(pt)z!&8^ z*gNB*$Y}^`g=`55UZ6AfznFiUf-7b}Rmu`u6&Q5^xC||?6~vT+sR>(!4i)58;I!cp z=#w-TzLshXs#l^>fQcr&Ie|H7(5D4$i%foVBcseATAT@YFeU<6YjJ_oM*bx9&)7tB zBwTEwFZgE^4x%pba_iMkuYP>x`bVIt(IX7rJ6w%Gu_jUr(H!wn%Qc$aAgU+h4|X(b zHBhGA0WCZ02G5D{3VCjq1q8HF6A05Q8Rxy%q)33 z-SQ5b2+AUaJfIZ|5ga@E@W}u<;(h z-cQZO({qX9dSUV2!uDbQ>`wj3dG*CX=H*W8>)WXx&vM@!#NX|wzTAzy-VVRri+ppK ze0P|By`T8f5bC!Ag*~sbb>~LOH4@+L&89khHf4!gi&F$P@o!9>6 z)#@)_ZXc}1|M}+&V5Fg`essV7>mth2b^*ovBVLpp&F%nG*^(46tndh1O%h7&xZYtnijLb zwM6!5vG8qHnmXhdZ!!PE`(vNZ<5UL0l_cd*Vl%r`5fr`9kPo^PkXoUL9B@hYYvl0v z*@P+tSv|g4-W-GKMw_vV5thDM4c(dq3fDisU3#|bx;a+y!xx6)L(K4Z?99k`0VwA;qwdj&j~c1YZsYC}GMv=-1F;*mPkYF=Fg( zR-cF|3?&;$;K+qT+&YLR#Kj~387~k#@enbG44IDZ>u?i5%?SPnU5Ci2vyX*KyW{tN zdV2QVgLi-Tn=k&|Zx_BkEj`=XeRKTnzyFJqpPo>?l0GZPFc~#W#b`;L|6pqJ`K{DK z>EO}c&;R1b|LgzxU(a8k+Y27Om51~pxMq+}37ajVCs0=^l~RGffKl8KDD>{;1z#bf zS0EU~su%n-ZV_0{LVtxowk~oDNNG&Rq@nhHaw~ussx8dU*o6U?aYwoU-wXUjM-ncK zz+k5@^v@UkGfCVJ{jA!jP)62wML78`==Nbv9SSa9C3`-jHSNV;}(SsHE2LqFZrAN0{pC0)q@`^ax z?iB)?gruMeT#CZl$kM}|g@-$-m3n%vAPs0J1`a?9eB;daxWO*cXqjON%hJXW%cS)PayL6gS!2 zh)rXfUHoEHnJ|#UI-=Fws|^XY{RVqNZgX+1I*Q5ISD1;yNcj5y_;&TtW^g>F&f8<> z2L~_C&R<;uKaB09b2Kc>*m-diNO%N^L)GIRjzOgW7D$=30)H|2q7Z~?WO*m!;gupz zV!qAN?)SGB9&C9>f{>XZ!v`+_SI*9{@y#g<=y$||!P=ak%W3=&jx$XjO{@^m*kl8f z{kg#uSIRQGVc8|44+z9{Aa25O0$ma;b{k*N&0)8x^*>ibib(NU8jjoJ=VO9lAs5a1qEvd=E?!Cjg z!xg1ZA0A3B9Jl* zcB(0@D zpGkydPV@?)JJMeWqagy-5_LT-XGyK-SVZ6k!m_|ZquQxz4C!pb^o^Vlyo0|%%@bf6 z0F6M8I#}Q(G+2F`rL;zqKsKEbjVFLjp3PD8+({y4>?34mDexBum?mng&ZU4r1$q@U zA7M>~m0~qDm)a<_GO+5saBubEi`|KXk@5ZEz?hHgWM95Dc;#~O)_(fcrNXP7*y9z~ z^G)x)MeCDg|I5wrtBv5x^8q08@*zt)^^Ag*K&3ujjJc758*lo;4!W0s`;I{;X&uYFeqd)`wvbW(M_L8ZI)dcu^~U zp(jMW%?5s#RdNnG=a`KEgnrRH4LoHL9Y8wh*!@Eh3@_)zgxF$#4U$x(Wamg!H58=X36@5lqCE`Fv=5eC_*h1|IIFZ?5?cri9~B)dCtED+_OKVn<+@&5QCL?_>_9 z6`qz)a!ase#6s;%`{_m$X|qhh|+)|))YS09Y%?^}+9(^ZTaV2yd zQ;{x?qORta1_+_iIM#%N-`V4}XO1B}LEZ1fqd2uO5M3)FDWY;~C9pk&K>oqooAV#< zl%DJ-Z>}0=GP&)^xf`34w^oq0q4LQ`7K^|7)7#(to(ZV;B@yc(!NM*WRpS_h;SR3ub}3Cbv;(GF+G{{icR)ne zeXf_<+|^s(O|C;%5vXiDdD_UexF8BeDGVMOIO=0rMnvBkHe5Jn0H7J|1a=2QL6c*} zU=#BdR4TsQ2?nn83{lfgPT8ViN`chEqYx%rD>eqYX_TpFucrm^- zgl#F_!G+BN=y8pc?@JqvR*nXYlbkG8^)WPkc=6yRguDw+(G6PLjJ=GARB_4tBMz~L zCGoJdenDc;;R!34oJKaQo-1mTsF<#hJJH{tt&~j;tldee{jGH2Np^e;8D^! zgzl&gW?>$)S*xbVH6&|Dq;j)7IlU)qlA}u4B|{cUVLorkIvwQzwiT;4w=TcBId^3v zHQm2@ZEJpSS!GkDONnfMG8FarV(w~RVIkzrdI}SnM9Ck`*cX>8p0r-BrSh4L0?Ik1 zh^Tjp7kfn8u@U&r6;mbDfBQ&G!YFuR)(6z)3ey}UI%s=Dl&~l z#Bm+Lt*A1ga7efi>x$_Wdab&S8eG^HBd-#sfEH@q&s8Hdx{QJD9taM>GsA)e@(ra7 z_#?74KtAKbBM7VBHfk%}0bDr>++|4Kz%d?{D}-5LC`ONAYsYDjSD>MwmPA@RoJ}wq zLo8j7@_H$qt>Or@d`x`!Bg}ein+$o6h=ghtQ_;QNC?q$EsnFz{Vs_#g+peI0QU4{P zccrQz$IqaE7tg3uU!I0VslB$5LjnRq zf&ACq=e}t83ZE9)7rd}pk@ursHvjUfVm6=MU!a>rU(|fjCGK^PCR9Za9$d&duVu8t z%+e|CJB|s6O@bd2yn0PXZ9`xC@vd_i$x&T|`5HeNY{78C$2b5d5nvQHt7?{JUwaF* zWE{c?N|PXJjGiBzeRVl}G>z^#(`3{+oj_MOQAI(R52Aaz1f7V{1NVg_J^U_uXiX$a zeQooXkOg)z+ZcXk{zB^T#p>pb(b=8+&DXnQ7b=LI{N~=k-D~-mw<>S1^}pClzPJ#5 zydHSE8G5|#d3quE`fB#=?f&<7%Wtmb9-sF=-Sj=Y;CZ~|!-5!y{Qd3WXBYeDit6E% z`0d5S%iYkcy)fSX>RRrP4@W*-Og>(9e%wyH!zjIM|8N+=f5rOv{)NcHoz%ti<*kkW za8_^28A|)Z1Gg3(%UNc|K*jyOF=AaA;8jA6PMKwC01SMSLC~P&CNFKIzd7U$CeA6? z^)gnMUG;^SO3!)a zc^eHdL-O3=1fnX+w^q{E<|CKq#@=1^9!-IP32#lf*M@#cZ8}S+6R5a|bkJnnJ-zMS zq}FaKnx0#Ll`#Ev5gJ+%X5MkOy6)^eOQ>#0&onfC)zkrvR&9I7*JNHh90!q&im>cd zj7216kFw&!P>+e;Ih}WoXDDV-EjkF)Yz)Gvz&_JekLy^|DR4&!7^jFCG#MLl;>|5* zk-gCYp1ZBKw*ELe5e$Cg=DTY~9Ko(F-TCd){++R-Pj`UGLpPSam{QkfF?UO&gy!hl`|JH^js75qmWG3mKOKIX-cuNs!%T`m-bO6gI z<{gj;hzvpq52j!ahe)TjSDi;N`7%3!#S}^l-oXNwuVl)!Jhq^hE9iyl6*P4hv96PF zuA2;>h#*r5MsqIo!jM>K7;NofRjE1PFD@vrP>qUy2WTU~PD4!%7cfQKiz+v*O$7X< zi-@p6;XHtVDJ&wPU_s9^GSacdTfDmdn}7NJ+N}#)4-W7C>dEfQtMk{_pZ($OPyhZq z7&#Hh?1su^wJb{*v{|dO;zKAj9GBqz;BM~L(GcW_W+f*zx!|k4PMO`va~OHR-$+1Lbt3;PrBmyw{= z^eZs4!-h6@IJ(Rl|N}M5#*Z`sY)Z@2p`fvG#ax z>dJg-HaU;R@Byc{f=UiMwAMPm1OsMdERtC1Pi+i=t`})ITm?gJ5@8E`cxwk)XWoPZ zxmfTDnVdX`%@P&2#U)fpd$7iZEemB^!02jxqFs_6iUtCCs zmI}I{8#mdQ@qSY%uP;uApg%{Iup?qXOlW#4K-1=sJ?Z)}h-TBOHIX_oH zeiz0!o6qd@S+xfF&_pSa^uR&|=WlK#5z9ES8dzT&N)Eck${rrCmCtVC@Y8h)Dpfb*(3n^NgSgl?7e$RCx4AsC;pVA!CM08EA`qNLYZY7r6yh0*KYZjuIPQ zkj$Xt@IH}EP*~;2vl1D_2m|Tn_kczN`k;;wPbaWX@Z-Y?*g&kMh{;IDg;EQLSfY>& zus+pR1I#+sc>HAh=_W=8+yrf?e--x;WQ6SS5yFh~;WU}8du z$LZ#i@a%k1_Y0PmV@udUiJz#)BKS1e=9+U~ov1y2uKwiN(_b~#L9Kf7Si^~CUauf* z6?=4FG#ZFZ@BEMv@gj&+{-qVBJdkdxjRaV_-=!g`Jc z0khm5EthVQiY#*I%uh6&gfST#ZIJ3;wwwZE+}PWM@1?fuOf`;=)73(2hpQJMlg*4S zWceN=oI^lUlbDRMPN;B&$SggWRL&$JpFnL5h$A@Y0l1o=8sP)zZGm70vWM0_#D<*c zBAvw?!4i{D_Z*n=W)?!5*GI10o!mYs9$XpSxjc5|{@T4Oxm$ZN45ZHwQqL|#Uv9?$ z!7q0cZ}y^3HhpidWIlZ}@a|Ue_2u;Iy=e6>x4lo!d!KIwJ{)C!e}D4r)ynRqZDZ8> z-IWYr_ov&Xk4Fhi(9hOf_vg)zmTd1fBd^x{4`xj-wmi?y`yOqD9&X1UALQ;{96sEy z49gMMuA#3D_=_%*4n`+_iEZt5jV)(e z2#8p3#rgyHQ3s)c1RHy24d@`8Gil6DCZL2=*G4$q)P1U*a0)si5KZuAwm7)LikBYO zb5dsP{lO2I$J5YqqZJOd=_C~k8SL$x9==&FcW4Pb$~i*g+0Ht64ai)|XXd%S;S~Ju zu)QBU``049P;OJ~|K@)2aH_aFzKEuYx$KSa?j63n{`dd)zr6hY+aLeypYHzQ?c4wU zmmB}-Luz+w`~B^a%gg3rudU+p!8EEzzJv`P8F@ryDB8kfAwyKdQcKWT!(3QY;P_;oxl3(#-IM<&wuyd|L!0E&%b~C@!sBz z4NP0!q*;@(AgmIN#=ve(7~9?fTgihFxJA@~PUOUVrm#_=S=dOnQ6%)0g9&s8Baw3a z>f*&ux6s?Tba`%QDk;PoS4uF;NhUz5gn+@;Yh;2?cGj>K=!>*RCJ} zf1Ro-{u;&IM*Kqs*=^=v1a_JE;GBIfIV4y%JqJNpz~6Y%>IrIW4w2t0HORXyvJRWP z4TWHS2iNTqK+u(N3j_K-qk;g8gB?lY;tj7AZLXw56EC}50Xc?Thna`@u{fI;Xwy2qMt8`Xu0$<9Eqqd?N(cdEA&(Lball`Nt`9+EXgMsemj?F6eX~g> zUXUrPBI~5u#qbSzhN7C71u%ieWO(TC7*9>4(-UbNS0H|{JGFcT8yOuqYF3{l+$VU$R6Ob>0ottv#~hq zzz_}6^?2JUNKnu#gbTDAvOXGV9oCFb8?kXMGT<+$>67Hf9@N}$VEn1ah}{g#C7y+p zA~G0Lx-``z0on}P&tX9Zn-bEokoJ7K=C9Fo09z$hC&+G0qF)IS(t7GZ80SHrJyh1k( zjALB5R)tiYI`GBd#8TT+*U9NZ8c7SIqk-1e$n1jB`vjq`OTmE87qZMS0^9Fyg?7e- zLw;t#9$qi^*m2_NMdDw0D0JcOmL+Y)y#p!m`tCSLCaUvBw7?8kq1qw?qb6Q8b>?yZHt*^0m3^1rzd_;x?~ZY%I~ z$^LlW@^sPm;X?4cz2y7z!3Q(Or_0tSYp&;e@%J|eKHZ=G)uXvLPZqD)JN00t z|HeXWZ^AHgrk-*Y` z^oF?FGnd8$1mNgjEmQH4 zzxD8s&!7J7v+QijmABcm7WaUsxKWM_2XsLNx(}El0uWPU7o!A_rJ%vCix$E@5#_DF$8AOrb0{-Gc93PR@ zjx`GK_p<~VPb5Gv71j+I4LvVp0THqXNF5+n;i+i&8i2oWAwfHe?HhzxsEva=qkn1O z)gM1-qvp^^!jkjAAb0Jjr;q>s(@+27?@`yw@yQ@hQl*SYP}k?}6a$l}=!F}4?&AEL z|MVV4ButB9x0qw&DWV$Jke_U26HE+tNKv{p4LuvsSy!~*{Neti-#;s_6vtOfNJ`Wz zNLpmNh`UXqE-NSQoZf>+(`P!Zf#hQrE~3Y+l>t^8Jt zoDhmB19`K|%0$-X^6QJ!kGJ91j%=1qqXBWs5L(U;U7hEn!aiLU`DA9Z2ulP7)MMeK z77IKBzlGfnOGSFAh^Q+_m~LH~Pa@t*OB-3v9X;Kdy)*?er@Lr1hvbQ}!$0V>$J9a% z8CoWE4d7^JOWDO*j?t|K1P9Y@=!8`ki3}@?fB`vC>A21tRHQ2INY-q(31woU*20IH zOKlWbT*~5L1Tt@nnddUGvo2}c%#C^l6C>Vi-e~vmjZU`N#&II?kKG8e*X&Uw2NKyK zM0P~24u#(>%Ee^}0W*XZXhXJU47Q8`os4n^m#M(kxWi(g$09N$2$}5kKthQi6hN~h zX+e!9@YkGkSqq-rLOC~G*uA@F$@^X92q@_Ia7LgLd15Y|O=I_%qe-tTXwhQ4QZeC^ zilIS6!^i}+@r)6%T6&LY?Z(2jcUN!z`tFba?GL%FLF9~aV@B^>9(#7WOSW=v*FT!T z69#*HvI1!a6oja|vmSw7NMe&1LONf`VTx(MO^Bv|zj)c>El!@`pP{1wIZWnsRqcM< z4$NG*V0A~r0BRIKFMozwJZGxuRrpuTZgAHCUtlq=&k&3|2n$xaf@O-@v_1no@_oGC zUPc#5*n?aS$f^+>DssqLIh{lqm1Po0p#(-SvV?|z2m}YpBLW&LFbvc+t*4M+iADy% z89o(eY9RG#eiy35S|z>6F9P7go~-g}Ao^?4>rq)aWIX>=AIl4-8-MWIO|+3CC?8cUgKC#4W#}Ucq=Pq#Dq3+ zTfgo;(b$K6bF{|PBIz`dF;C5=9zNN9_p6&PUhe$n!`{nl7}w%YF2vqkDm;K!cP|0W z^Q)cs`~5VoZ!hLv?x&vZ1Bl~~fWLcDc#fW52tL~iz;^U{H}c}V53}u?P2b1u$os9x z(>342Ro~++47u(XD^6U`7j4fLtgjaBZ&zI3ZunlUd*498wPby}?s|3J_jogOcPoB* zEqZ6sb^Ai})tmJXf4P73;ShQL#;TXx0ns=jEFgU{3vH0XU$(7GW%p3+!+pb?u0<4@PA zlTCl!#BKtWWSj`IQaV=3fXsRD&r@%%q;IV{FAQU0ZJMgeuIiW_UpF3aKxbvgIlP4e z8Nw%o52LXQb1_~RnA%YH)1hIo98%=kooqSQ3eZ7oH2IuJPL|mCs*nmn9N0*5GA2R4 ztIa87rp>IhotJmpW(%mUKqd^)z%Or2>oXohJ`kDi=Q~tHQ6CyP!RMeJ8qL3*T@6q( z!mEhjI|QaR@vBXyf7SG5x06q@g zYK*8&J+ziSMmrN}lfCr-U!I1AbujF}2z>S>o!}V3NpdB9Kwj`&IPl|(gCI23Sqld+3Qds+oMIxZ?|jvoF*m^(`%xEE{5_M7a$myT}|@qC|Cpoe|5q( zy|~M%r-vP)fJ68he|-+A+amPX#L=KG5;Fy&hFC;n(bFsnC<Z-NpM)` zeq*1OaSopfTy(r-1^CK!6z6;*u~iwqv9SOBE#G2VU3T<3xxARFddzc)VA@6ZVr;2U zIGPrxP5P3Xt4HXBq+3C4mlCn;Mz4^^!gWb|TtV5|(Zs9YJ$&%v-POA*`h(HDzZAbw6q3^AuTprboQ-ELV|(#?+q#3&iJdifG1Q3gA(upQ4j zcg&O;jN2nNsH`ES#%|qb?!#v`_$9%zGcf4(lqx-a(#HBv``F-QteBITDsT>uG+cXltMsUWzb6T22;$!8Xfi!jY-6C$vHCe7vBo@(&w&3I zP6hCEAgdWub`{wfofweuWdjX~8m6h>)urrhLei<8S~#8%M(Qm3^-*(UUo*Z_Ow-5C zefcHazO~2D^9$SW>H4pKdFrpw?uXirE(y()4|G!7VPC=ki~KsEFoa=9;sQmCz-qXg zQKo=EW>!E4FXstz9cr3EZxZBv@HK}96KKOh^Bru+_*W-Se@Wv}ol)oU)*5VhRepoO zEICK4$6)})HyHDgyaXGs!lTD0$N$|nl59ptn@a&}KyalZ%{zu~u3h|_r&Bkooi#2b z1I*=mWj*i_pzRkb5t&nh&X*2mqtPcDn@=BJo_hXddw+XicW+>OJ@x$h$m@&w*E_L? zOOAKDm}k?UZVf!!iGy~2xfR9r{xI|ADEszG;pKMd)mHG`ZuIr}z>9V7i%tKNRX6s( z&o(^I*WJ&S9gpVBcgJ=2XH3u5y#VOv%MMJtA1?%7E<2t~8=uXZ-z+=dued&JhrZtp zecW(;yYBjSJM<2p{MP8htHZB%6Zg)?Ze6KdxjnOXZ5F5QNzj9M3WPbsqyx25tE{irEV2y6bNe%J^ze&L|MsZ+!Y~pi;DLqf7B-yh z<=NE!I1CzHdU^+^1F|28qbS{Hgscu4y{Wn9v;r*y8KWR;LWdy9Cuy;=aVUa@hgWc% zQPNHe5C+;+OKSL8CQ;W%@9OJA{v!fsYOr$wzk!1m=umUaih^2BK!xNhqNEoP)5~h* zh>2uUb z*M_!A*bH|b?{D1S1|yA@Tew-lMuL|2&&Mqz9&ORga&qvz#p6QZ7vpK>>~}!l;?Fyb zUbvSDd^H_;zgS>t9TFONV^$l5-c0AhK-7pF!fMlyfDFME#vgmgB+znsN+wrMN7_c! zKmq!lR;^>hJ_}?T4)b{X`D&+E8({#!Ra%>hj+h1v0wBupctJ)qLbRx&9;9$U{EwLz zZG!|}2cAVt1qFY5`Fr&2;=;vwzNOkTh?WZ2uK>Q*ynW(e>hk;R1KT5^sW@O4M09br zwDn*cMG$fa- z4K6*ej;Ike>y_PlnD&emo4DPkB1&W(DjNeCm1;wub29wmpFYlhvp#)yRS;8INBxX| zgys`*@|H9FHiTCr{zX@CT>0&jyMO;4t~9(#QJvPI>SKDP%D4`l^?DN%re>kIMQ@>} zEB5?E2;tSyAuq;Ev5gxY_s05dQUy^c?XIp|14`s?Sp4ch++p=-bCuZQ#v~NVh<66V zTpUUU49t*EhExrENMS+Hgr12~2{X(?2A<0y3%KNV9CE$#p@eZbqAUBPaRte%Ab>rH zBsEGaU2f=;t9k@{7-zZz8Czuzu>vsoF;p5FcH(wrcQR#wM$4NqIP)fV$r>6!9Hm^U zqZl+4v!*xU6C}LcsE?b@Xq;gwJ`BO3s60U2*~;y$k=^O3y}6;4VPw|?#)+c8 z@wT?@G~VL)3eaRp=mYbE>9HKgv1BKxhpHyH`a+(OzY194$^Y)OuKA z>nZhTyHB?;+A!CE+&)(S)!Eh>Jg*?Z!b7sDrRL~0M$R6zJ!CyVb_65} zBL@7+63b=ZWXdrd@lRHxK{E^a&|na@3-n?@`49X>>^Yi8gYf&K=%abd`>nvc^Zw5x@at9A z_ZLDRH~lYG?H{*1pVl0&W(?2gthZ+DyEC5gvi{C)?&KW+;>rAKl$x>a z;#PiFE3+9}P6DlgDu|IX zW4qs3M{C2?C8M4YAf1LaI4m}*3>k9jZ^3sb-x5BbK&{b;meEYUp5bi zjYED&&Lk0ycO(o)VP>sd*cmen`YQXAh}~GacixCZUjx%M80a-JQ!D+}2|q6)8@xPu z?KgMAGttUM|J2?Hd=@^8d;JczU!g!ao~)OnWgtHjWz%Y#2;*>7!`xd7{FUh0!G15) zP#Au((fL#k8UkNN5rl1B3#N0>>BtP_5V4-a}Pkb^< z0~MxXOdc+-+}!-(Uw)gOD;&MP`u)HBc;|Z~pbiAO6etFMs=tYvtzV(nvcj&8Foxw$Ue1Ik^Z<-`gFH z2ILMM&8ug4G<{wz4boJ!F!}Z503^y#EbDsh8scaCwWWy>fHH<(@OL8M3(LoO)^8DFSBa3^$5zXF*Rh`LG-g`9S2CTa=T zBu+IWY~oI2th0IBU|3bek51N|jw&GCM8H=H?buEpjakQ)^`a;_H4;|2#E9BJywxBW zU_)QPDM-Y%7Ox1k6!1YuN_KldimkCy+Kr`o)Wr#zDIq&OomAm0asKKoYMK!*1N_DO ziz`%#L@SZC{l(x!ZtCJ{et9@HlGXW5@lsr2l-qn3V3W)#)A%*9N+6iECo{HZk9I%3 zxSTILV;M6>V3Cm)D7mr=nbE^36yhLW%r+c_VH~+t0~aRG-`j%^9Vf%+Q~~LcIPLg~ zKBY(5qoTl=kJ#W?VA|kZW8W1u7 z2u43|b^QFi=cTp*c5z`4#x4w433LM^4K){_7MSi%d4RuapB_^%*2iKEzl+>LmG!}) zkH}D^Q{m5e_!thot8eHcGrM_!O|5`m1waKe$_^4LzY(^cG-RH-I!#F^{rfzIACm%^qt`lkp9tQ0*50GKjUn92U2xEafl?uTjqKDu+h*W=d;AmDQojh0)?_IWiiJA~Mb;h3$Ru`pV$W zxZbCX4TkbF$$`ZTUQrGwGZo}d7W6M(&OEz6bmt)a4aW^jGDl!w&n<%aLu^TBUdy|_MZg&1;1GoHcCxp@XC0OeX?^_VmJK@*B>oxoL7d*dOcf6g}eOU3l-bp^cHhO8V zw0JNuwV9vWE+2if@##N*xcS|^^DnMW-`mdZ%(!QZh;F7w%%Z$cS_~))K}E)=m@KHL z`sEXO^~#80XO@}|bm_&WpcBc@FaopCMv-1&_e;o#;Z$r{_@eaZ_<{n&tj%Z+etjew| z_ZK$?!L$rsn_79X{qEntfBnxNZvJrVZ~p5KLmNe3!R#9L8PagYvf)1h@PT{5v?#EN zRc1aSrjf1`n7fxlHU8F^Oh z*1DcEwWQN6G-Qduz}N^gdwowGJPWw+7^xC#uprS|k*$FiLh#RkU>JcB?F9!1HoxYO zHa!^DI;GC2(GasBJW%P^>SC521r7L%0(xXv@m;deM9Q3ZU;F;vz2819?@f$fTM))H z$go1X=Em(!II8;R3#&KQqLT^egpr$i>GhSwRATJH$m-Rl>8+7xpYDD5?Q`Tj7{aQX z&kq0dzx~bK=LeVXZ3K`cnbh97y^0klXk;wJ0KPsQ9Y7qgaD2L6ueJxciH$Ar7bCDk z*MrNeCOTzZz+aQ39Tc=xMS_P2lr;jNf?ie7t?=5!VXw+=7Ko+2&_C-{y*g>9Q`sFe z_6C$4SY-sj5{0BLKi_Gi1B+dzKBJ9p35!ET)8*TX0~aa`3%#^eR>YJYimu{z#WNA; zP!nMNp18A)JW_%L&oLGfp-1kYFW+27#wMw{Mdp$sN`&N)92`T=s0qokc6Lxn2+F#{ za*~zTK9DpAeM*gnUtO3vQo4){g8cl}jX0_qv??d_?I}_XN$H5@cg`jy0kv%_o9+v%$(zBSBh0 zvTAzMUP0JMMsAqf!L<1VGg}p$vPO2sr!Ox|94!oNjylpVLqI>aI5>W^5}C{+k)wZM z7`07UAlm#^v)iZ&Xi<%XyiIq`nH!Bx&gZUOSvcGpiKg_}{fXs7gk+|NgX!sndpLk6 z#@yZQ()JYkE0I~c_xRG@!=v%@lUVo$#|vzWOdBwwB?>P&|8Ov|S}=`zTG`!ThO0_W z7zemL7+RHDAx{KHK|PkgKs}^)I?U0C9Pc!X*XtGAa6@kO|tB;{--hr;xfs?*jRZ zEb9(75d$ywvslhHvI$I|uFD`eMsGXGYzO{!s_1BjLPLssZ9tl_kMGZiewIcDMlxcf z6c(pu7%=Nj^fHMo1?Q{glV7!+szLLGq>mz{BDb@y`|RgNj26UywVuIcDF#7(pn%ep zabbU*pDm1Tj81J&&0k;n=7)z^RlqSZwLO7?$gzWIq?6@PMS6J&_$$H!D5VO91a@uL zrM1M9=Ob@kjec__^6YBl&CS&BUeEsK^}>(uH-7l_`8Q7|-`pK~bvX~&73N>8fPZzZ zRNep1Ti>p@zgzdeUvhoi47}S4f`5K~6nk|LeYj?SbHVrB#pv5z@ADn^lM7BHVtqIO ziS2*89RwCXUva)Y@5h?>@uK15rt^oN@%R0*`}t=4{y}MDDaws2LQARjhg+B5T)q13 z?Z868x|mN~TeeMP-18-QC1hJDGm~~$dYd%d;=!_ZX;?Ac-{4Z$N6hNoS@uW@iJeS^ z0BGB75IE<{vZ2^9aW7gJC|W+Kd*pLUavr31w`y4J8a5We=s{pur3mok_WMW?gBBi# znT%yFBP)9ody}YFqk6>1nov#0{5!+g0^5g!kl$z&G&1olE(W!syY(2rSKQZVmEm;i zmPFJDNrq5Im$pEl0!Xdrv?Ev;$_FxPM>@`(?Ko52?{nchtA`K^bP%ep8(Hnzq!o3{ zr|6A!oR&UNvKmHrUqc(QhK2-1P7AVnOd%DByAF0ULYx|?b;g7VQV`%fLJrY;B~Lnp zJ{>w8a6YW*u1XN0AAo1AkSt{YnVUQ~FVZ0J6Vq^X04heP`_lAPVK zl)Lfd>Z6YjZ@;-Sx;>2?iQQK>uK)D>+TT2X@zbk+_`m-7;O*_Ze|op}>e}MtLw&yw zL|Ntj?7?rY&fi;j^yjCC-(6q$W+O2c6)Gr5%QW>@(OOJw*nI2Bp9e>-w{6ORuj*cE&b7Tt}t^_WNVk7iaHnxW>b> zm==0w=YY4*#MC7W&a6upG0HqjB(&^4y#)HgRP?~aQ~bVq{@e#aiNStCR@i zQpCaySXt?yGU7(}7vEzQd5l~LwA8G69kXq)%^huLO#J}ir zHdo%+5R{x&^%T3u30S$BU=wb;DS)@%C2Ev1*iD1-JjwwO8hm7<@ScS|+l}GAN z+f!NZK+%&3so{VIZy&~<$I$0fbi2iEVP2zG)P^5sBrZ=6*aB&_Cn#ZY>U0Lm=wv7y zSE;omovtV3;(+0I$T|jworRKFYa+)o+DzGs+1%*m%d9l9v>ht7Ttowg9~ou2lqrv* zQ#j|cc$Io9&lyx9 zJ{lIP;mH`BW%!&R)tx?Jx@6_4hyqhzWwU51S_}gYr=mh_4l%6*lkugw%yK{4nYBq10_%`)g~KYO5zr{oXzg(GF)`s{swLEaMm>c^ zw0gLx^{PpNEzt@fh|m49?H73D zvMmCtiVlxMmz3Bj>QoeMQ0Aaj2YrYTQ^_4_iAmPQB*Kr`#vnA-*VWdYBTjOzMrE)zV0}S;zBe6Ya%YG%jigXJt@cZ`ta1{xurYn zFg_f7yg7AymF<%_hXYer=lWNR!<&Op(HmS!yvS1pd$wYqUP&GuW*^-edU7rQ_QBxu z2j$y<(TkaHcTzvzT=>g_@*yb3%1srY+QweX*K=~{!Mp|_u6h)n5_n=0(R!C@+_6Fw)eNORNK_|^CIVb57r;NG9 zk|u7()kER2p@FgeX?6lrH6>}6E>G`a- zU|V}}h(ERoJNg9O9i1m=-KWu`jq)?N+pKyJ~yu(VY!UKTAA^ zwFqp9sM^E}2?;heEj2_w83)C>&eL_ITCgkm)xpV|>yXVCuP>Sx(yLe2U;XVnoWK!7 z@!h}v{`-Ib;L_KZvF06`SOx?q3E8;BJ6$X!`{e^$--vg z{%;=)?2n1_t;7mvM%HnWD-z zQ`=~KGTuT=0s;*R&uSJHVthEA)#b00BGfVD79R2^;YUUto(>iB9%;DZ0}p0T+4WJA z$fZE;0R>B+pX-p26^3@3#L6%NkR1zo*rKoh^l!shdX3$HF#;FH~`sNyd_>8}w!56R#^!$7Qe38^)g!mbQo~#xJ@c`l%d^=FL!PNb=KPQ%W650@^G>H-6A2KQ0AEAKy7%Iez3h$8Wr4qH zoL)*HsFlDJDa~R)8`9KS%q|X_fF}vEETkGfoLoZms9HoE4a=2s#D?OK%ptl2g%{wI z@Z^EG0y%ORGcog4cVUEj>~6R+CRW3s=77H-nURYH5u?tjj1~gWX0RkwzK)`>vhf2k zdqi|myWGOcO~dAS~_Yk z5Q?I-OR(0);O0?Q-RmUZ&T1Yuu&Z|m3XH7C1HA@brxFZ{V}(tw7dXJAtXb4qxv*lK1# zl8Sg^(7UNpRxNrJ8|%-UJ$<^i25DC(>ra5zMtBi8XH+gCcoTIMaE<_c zKWFJ<1^i{>NrHf$7_a0PCX_*YaeioUW$@tcg^~RUC_pB!F2HYi^QVV}?cu3wi;H(R zvP-$tObSCWWGApOLe-Dgz}#l;{)6dnUo5@8QF?!8;Nz1~05SB>-yin>(}yd6dc6Aa zDF0;H`C`NMYTNf>FZ|>Eq3`*qi+P0z0`_&+ULAkBKP6MuAn?&jn5rK8dHn+uDVr=~{Y zqXWU&nZ){fK9w`Z(|AO9+#xe65$zR^C}u#nqj@SXD*0I%i+v?;951w^lOpOAL>xqe zRF@0)>Lq~SW;x|Fx1&Wt#cZg|+655}H>m7$3VC)he2Xlbi04(*aNAlnv^E{XI+<{8 z4*B=S%_~LALe9CAb56xg{Z4^b65Sm(q5uLNxO!TjOW>MK_@?7j9c1zR2Is$|Fx5%&J5QE1?H0vRFQ2eXRP9b`q=n^a$ED8cM$ z#_RuF^Vhg3AgD&m7y{doKY6SKJe+%;qRICRZO`LLkq>pI-W=vzGA$ zCl0_+cUlFGneh0f$&vHrBL$q&8Td~!xCxS*p{%td20kFNQ#<-E2VamfqkGCMw zaX`gfjQ@%Y(n=T~aBjyY3n+{S2=Es_L!>}s`71E+Al(7yDKxUUS{mQT!i8*Vd)gA} z4`BWU{zCjLaLC|FP`S0}JeAs2cRxMZd~yYBm18Eo`uy+@|MTxY{qwIOKfC?w2Vj{{ zGXY63+rWav5zKZivqga@G&`^i>H}7Ob*v64 zq827TCamp^XowjVA*LZle%{#nV^Wig9nb1y>TWg0e80#S5ZfFqpNE%=DWY~()J*fc z*yW;Wuwv^k+rmjzVaSy%SuFvP#m2~`^==bg&Z-ws&k8wB;h1)2DZhO%i(*Hfpxfq< zdcA6!O=i*yQgKH#X7fia$x;XnzXNmq8i$M_>UARb3w_FQoei1#18%!l67))-wX6QV z(wbz>h}qoY6XeE&nYq~Pjd>hhVnE)7Tw$#enoJ~DOXJs9EhCZC)+mG)xUdX@&#QEP z7&jDpe$l}l8&34et7TymKUXwTXl+QUVL&t7)6C%X*t`Z$%mxu7^oQo4J~NiG#%*{S zU_k@OMt2E@Stz4$VO|CWjVT!T3la&3SZEhvYtnkLAn?v#n2}o~z(gF^-BByrx0@Mf z_&TyDp|Q9H?vQ+AcjWq`t^TRV_(~x?{1BeoW8Gq}>I!qP_GX4Bi1g(t;y`jAZ5M1AM965OBT5Fo% z@n^N*Kmzf+IcY!Matcil>X;4Y4rDUd!(VIFh|CHs-C){1L#;nWt*2P{ty(Hxv@o#D zJUCz2A4h?gz@_R!un(F6l^i@9PZJxDVMu9esB5f0U4Nz;I^9%*2PUkbD8yll88AR0 zoZ(DMjTk3OdKbFXktHZGt0U#CJ%a*oe{7<>baiWHZ+2v3@WTBII}dlJFU}U$%PaRb z_upKFA{r+8ofiiP2atJj-r(}}43l3vJR7Y{`5!)A{P=A7`CbC_t$jgB zd?g0uZM_A0)mucb)_bE!H#DUYW?o z2TsxDJ>UbI#9i{7)iIg$E*3nqS!A%-CR3PyJ0)b0Fvz7*dDQllQ{YsKU79mhL&2Fg zLSu7hUA08JtFBi;hKMV_UY2J}?!{E)?y`9~Et~X}j^@n>*erUI8zak)k5(QXB4oo< z2^OadcXcZxw5BCi_2BUpY+?!A_@$?+bUJ)#a zE*AFQ@SMb^9h_%uMbIm5VbwG+(3a;xrC!5?e_dTQzzE#tAB$X!%h5~63=5s-sxF?7 z_!R=GU=+nbVPG*D(TE}i5aS+#ZTwOF3sN*vfZGKCeJ(!pSWJ04OGWK8RGkdPc7ZXf z8(!&;^n~PIl{RLwX5IOzuH0xI&Oe}wrzXqY>*M&{hc7MmoE<~)d*|f`Km5yI-~ayM z)kinR&rX073!mida1vV!;I9G>$;f?!DbsS_N5A{#;;VaK{KMP7`(JIDN98?>O3FeZWsMsfTXxjl|ufYr4zy;(3}0T)_|NC(NaTdazsyyo0x6|5f!mrPXYL1VHO+-h|!hx z#O2|V$>A08H57<(GRp;d-pmQh&AqIrg4Vk$(Y>b;KY;aa9kCLs_%e_=MO@oJ2&Eis|BEbs=Mk1(Zd)NXf&!^T4Y8P>=F zH3@HiU*0&_;{Yft)kI%dmh7@R!&04rl8h@c0yc^e4sb#*CC<&}4lmBc!a6|*fy=6O z{^&E-TMUf!#s|tsS+yiG&RE`!_ITGwHk9)yV3nP6=I0BJoYkE(gFiMhkxE82XlR#0 zYHWD$CZv*DYzZ<&OLj0YumuZ_f!WtS7@!90se5R2&o3AX+0)oM*Mz5G> zBr6>3M9DHR8Xg^w&M)Q{R!TjC{(<>)AZH4fY@J$)0OE|a*@%XTTf&sIHZe}a^cY5? zvs+VLV|k2zB=$}a(UCuun8|pD!#%5&2d_W6^yxXKfg#j)z%#ab;nVBT{UcIq2rb9q z6#&EJ(`_ey(fl*;@S_6>OWX#REf{99%|cjDH*hIUoeZhXqz~BZ>CMMlPW__&#HkL# zabXJtbO=m$Pi0bTJ<~T=CNC_Rvu@~%L1qSr9BEDPM!-#y#GuwRHJqwHUDsM)+gbxn z6UKAYs#jPGkQeoFP&1d=z@;Wfx+Zq#)~>AV+*+I1>Rq`o zb?@o*jcZGY`9=!K@P%2}3C`VKip^wjzjc+pnvg2d7d9iu>Va;L%>}**`w?AHRyjTYL zD)#hz*M}GSuH2ZK+U(9kAz1NO2BW=|$m;5Fc_`U6o`ru1$iT+5Qxmfl2SeHZ2>68X zx5w;T9=EVvQU!b`B6dw7!q7|k26f7#-WNp%^gqXY`Zk*w5WrR~7AwvR%{d%r1A8*Lpld zA$8foPwNtMIk{KDkuU)bnUP#>Yt*sYr=7{MlSY0(?M8r0Hh{@8D{j;bMz~=W(%j%i z*b&yYYFWn^HK!T1XXrHuzk?a$vG$W7Usanekj%qhk=G2C5!5lz$W*OCWpsDMAXYLo zRsmEzL1=kWMunA66}NKqY~+5zB_q8y0Q^Nv9xO^AVW`sVJ6Z@}{7R@SHK&!|29GZg z6<}wI=}C3a(+>W?DR990HwWR658)v?hnCT>X)@AvYtFmfjj&ggw;;St-rg>3jjerl z>61S^oxZuXclX?vzj^e&c(KpZoY=`u^eYhi4!B@zw5~vp4Tu$l-=)74uDe z2yFcciz#VNk7q!_hfgn@C+!JysLN-G8o+SI;He$?N3g6xi~^GY{6#|y`9uV!V6(@tuQDF3jxD_RRNGrppW&?F8!#I$em4 zLe5e5&dBF~dk<=# z5)xt~K4Z1Z}8t~Wa5tPdIcpT(#Q66^=J0}hwStAVxn7r$itp;5?2E-_VEkNgh2yJ@WjJTY+iJTFMMGSobLr4agqVEKU$En|Shh|3eRT2u!pfeis+FsmOLk1j43C&!{aWye6jZ(*r0xn9T( zxM#L|%pn;|-fEBQjbRN-J2h--n_T5cYO(6L2#J{4kzbsEbM)G z0VX_sJHv^wIQaJS>s`P8;iJ2^ChzW*KVFDD-blPUD80DU^YT*v)7`Ew&sSdGnfSk6 zpZ}lVUi_O+=AP|lA1-*nxk53ElJ<*r9~O?EpG#mp+mAoqj{|vM93-D?1|Q5=zn-5rl`>Q4AhjY%Gs}T%;QT$?p&@)pQohkM9gfVBy zjwB%a9oe5j9*s6>gW-8{B(t+Wp6>~Sik{?PIyGK^|EjCvkBlYE1NlZ}r#kGEnAJ2f z_XL^1wriMPBMro0tB`CH)k;X%2+@ojx)Cy-W-vJw5iQ6JkkC4ZqG+j!Qbzk&BEB;e zTkclH4acd+c_z;A{#bsiuOq2}xdcd|h$JpX_P@{2W=YiQemH^D!bWELA#0~N}44J6Nb)ha;iRR0#OHH1PF8h0}A9o zoDK9ph-FYof#2IM1faa%NI50ZvcY9?1U0s>I@TA64~8+jl)yqJr~$JMvRst#+^CM| z6bbT9qC*VV4x|-BB-qGlLV^ioHHZU7TnhxwHLdSgt87v&q4hNISMF0V5gZ_I8#E6uh8fVvSr`{p^pgu;4lQ%|CvB{_9)4n`4*0x^?%}r@#6ie{=ce z$KL7U+M}DV{^@TX|Mtb>=MUx=M=>Wd$IRFx#k+!qkyLRM*=#n8e;0szs6@po?-ywn(2~JekRL+t#Gqg;gAq@6wsb`v)_25~7v5A5d@QVI31Q$?4 zAoW}B(F&|G2=u@z2MQk%%z(nUhu}^E4hh~^%+Rau9Gogg8l*Lnu$dwuvb78pzaobq zJ(dI`B2@OSUt58+)7j<0X3tad`%8XIsHHwbda66zpPs+8`q9fzHg0Wx_U-*^UtK{| z&D6yuC_o`lsx0;uCX1aWK10c96%(7pt1>!Vn zXTO;lw(}EkqHu~a{6+KGDIvI|%}(% z>?pk(b(?b!J~`1ipxEjpgKUJXsI=^S`Dnzyn1Y389u4H+k@oa20;@t zupoasBP4W0RE(ICl~C_Lxx9OS2c{zEkVoK97oayi=3zv6Cz$w(A^0j zMh`q;=i$eLelBKU`cz~r%yYwtX?5~*ekn2&6T0>QehUQ=&e;9EfpXGnU^m(LO(6}{ zry#jyEl7k&Ss4*MDQ=>a?DVpmo3b-P4n`s-3B|;TqQMyv!%sUBmRGu+z~7)(0NPu1 z^P_45NgMByuJepuLcsI+oC%oXiOAdmK_VvC2Q<>4>m|4s4Sa~70 z$YErq@_L(v?lIDxY7$87xvX(=wKRJ;28OmRVH{i=m^wdeDSM=8>-N{zw;$hhEtQ

6bI*ge5EkWW%tB&dIp{f#tjRLWct$dD}<++gntHN+`wxT z(O^46Lj+@XUrgRN5?ENsF3x8rMnVg7>Gk#U-nrq8!``Kxt}k9(8C%LL?c7kokr|9~ zG<3C3ni-Dg#&Rgt=?bPZ>q07}%rCureg2#0S0~m>pFh8H<=X80bTSrG@a0uzDddV! z_qTBxV0H($WFqx+eakPon52}wYgg7PbG=}FA8US(EvCRinI&kdYyJi57r0lQY_36K zV7r9H)r;uH4scmfqd}hzO-FHK0Oobk@uWItLZ^#k=nz>Y&b(I@G$Ak!Zh;z??HHl% zbSs>ENCavVU>E)&xMzYe1MocqHxE=U7!)#^j<-U5(I7TTLAr)m*yuCBRh}!TpPr0< z^TiH=cW>Poy?u4`lMj||f3UoIesuBL?8McXk;9RZ!!eX{Fyz_4zqfOB?$Zammk)>T z-x~jLJNMaQ@XO^88p4nEv%k91|J#cL80o@Z-mQJ<+{|FL$-cThnZRK5B5!zEH0%zq(eUhPJ`--JG%<$>zD(UaY}|Qq!W0gFyb~1 zg$!LziBHCl>zZ{8qKazC*-;f@#ECBij~WSsKpD`4&?ALG1XV_E;GjT01^lfczSm4W z)y}NJ3HrBj4`G8j#0chhY`dC?^+dpSun)u)7itU7LK5tHAi*FxDE z?1{2W0;-yQto8Vb#$UYO@Cz`F(Kg2h7~k|SYyaGyvR`~~34(DbTfL((P|I#U`S8JS zAAkPCLfy4RL&o6!Xr(Zw$zkk2}@JfDj6doP!?(poT)k}}>e*F6<-~a1>{ouDR zCwCW*?rZ`60zF}5$N$l109*(xY&C@@30&-0dO@3*27_4$ z51A@17W&fYP9K^1R27cY+6K4)G3o%mRW>yc1bqV?6O}JrP30I^<@wU`l|@jX^Aj1k zN5U^%5mIBPhkFJ77HqS0{M=%&5??&OeEXZ*TQ@d7ee-c{JUxDS87lkzFRuRaU;mpd zsP*?oW)9}z1Vsd0r|1NrYoppWMSG`Pbm#58r~mM3_3FyR-Xvrr(ZPTn*$P1^j4RyY zMlbY4Xa(yjP#XbuQTav?4{k&#QkAj%A5j?30Dl3#U^}A(2BIC+zrbI>G4L0}X5cSM z;Og*K+GZ9tx@FDCzP8F+aGoOvt%OHVh$<^-eYs%n&YOx!O?OI{jVkPBhSkna=Jcq4 zp-qMpRA@4``}m45rDM2-XC%#kA#AKuw702guzhaSGt|AlU-IhkxrHfBt&~W&^6aD0 z?D?_swb{vAi}~4%U0daeq4VtHH%F8-5Vq}RPCR3@E7}0T9wTPoM7x@VCUDxuNtqZ) zHN`6;Sa~&GNpsqQ%9M!>0~*VIRdYnq>=QOv1@%4)FW?d0zY~eL{B(0ck+xYcP zyp4*csG+^+;Q@b3PA0@wQ5(IOQu_QIj!L_`XzZ*-YJrA(#-?sxm`s+FI zZmDj)(3CI>>W$Epg(Uu>N$eCF5{BGt5&HUpgDG*+JbHbta$(M~QnpT|5wwkf$bt1i z+`Hh&7hNiwGA@W{y5@R709H8UuuM0*)KX1{$7Lc@nwpx=&{#wUkBq%2=D9kD8jcy@ zYiT@cP^NMDL!bn&*Q)LST1a5-zw3W7y8&LiqYf~&*h&_f&tPi+e<3xhX*~f~*qPbH z%v5Z1rEq?4U|~8wI~`wHFYR3%UE9vD?v(D{UmKfCd6U{m(cU|ikD%q1G(fUJkx^mX zL07X4F*6Ukxr*ms|M}NnKHOVc&MnO*Kf5+}ZazC$viSUbSklp?NaL-oCnJdPm({ca zR$VnZ9CEyzH8qs-m%@K`>d!Pzr8A^cn|Tf+L!)SCG3uaRBv2Yok!l(`+Mpjamb|*G zLlZZHy{1bT(e)L0C5o69d3Iut;tWEcBvkBPY=wY(AcdJGMcDD@r%%+9TL^Sw4YBrg z^Qj{>G?H6kxAjZ3qwx%^J`wLCqQj$-t>u6@cD&_1om1LB6d9=4FKlE#I_$oAsd#-a zbA2asZKrVW=H$K4H`i}W_3!n>$HJNU?82>;r8{fLC7Iu>e13oHi;tGSxIXyxh4QQO z)rsv_dsRL&Bt_q@C4Y4geK==@Y1LQj(J$8`aLjnN=6$wgd$H<$zT$bd>;@M9>TK-I zW)R1(*8Q(my#QRWs<2+K`QB~>zTFBvU2?rzcfMS6yjr!tUa`MjvAP_Z7sY(Qd!|9dorS+ceogwTqvwdN2 z){Va-P0LPCWykl&Q0=xTJM~$#)V(y5JhM24a<~~@WEMV>DZ~kjJYi;<`DeIw2!Wz1 zC~Py=HxLSq#^WJZQ2SBwumTK(X#y^gdiI#4og&pY8R9$ zXUR5mb7At*lrL>WLaRtg<8=}^%o-Bq1QN=+=5vXD@9bLT;)TiUS7vv1hliHC%za+n zKp;F{MEC`S8<^UlX;8{?>zDB_;!c z;i`%hGmM+hv>boG>Am-xk72irWKS}^38XLVkfAKd4`zB7dU=Kph-kk1FTaAT{NZO; z?tlOF?RO8xZfxBC-J=iw=J~<5pAB4D;ke`&xL{7Y`|*W~kM5MV#`@21^({~Bp4&#K zUaSxf^~T)gfY>RsIi%cS+A&!c zK&jUZu`py-xB!uoMr%aJ3}XLAI&{HxD1jT!xRWjA7~| zgWwm^kyQ+pN17i?0m@geE#nRYz`gbS&Xp%OzWL2p(+4w{|Aq$qp0wVC!LA1KSQ0Fl zumD3xkB;yc^)K)j4QGHakQd~uqY*Il!gwXLzyT{C(MVNw z5@^q=Hh5Q7Va|*Zb9LH_o-+o%U1?pVWCi}B3yl_Z)GKgWSwsLwlp zXZh@ttNz(cla2=br3B^f@#N`_hLauj1Ot;D(;VkFlGHSoM*`RD;#x0grIFqKgWr5| z{`JlDWWuCqHwv45vUcFF1I|OddMIkO@Rbrb!M_@&(?)3%q|FXlQ&>$zg_}WzE~pPd zDkUa(B!mclcg)A7O>S9(tMjytb<)DG3)p#HE39F8Hcpehqu$1=a|s&*idLVp*&`=- z6@-AMDQBf-%;bmxPMegToW^FSi?vOGTs2I}j7^A}ACJmQ89fNnsDHy+GQMw2*@lDh zqHS$1gEDz|JX#s>WlN@jkMFZEFhd9aqKBXpHin=J#IFGHwU*MAF?Z#xLjz%~KtSR4 z3S554z+`Ii>{#DqA>9>9=fhP|Qq&OhtEcCDJvBoUUl)oqy0 z1A-k|vP_LgG6G3M&CC~(vW=PA__gKC`k*9j1+P*(92&cScKYrnd|>+52KGO{z(s&k zx2Li`GPpgtar-P-k(t3XqN664hutBwSjZ-m8r#VPI=hX{r%81}geh>Pta@gH*eXH& zi;F^Im!p`4?f}kI0AIK|1AmX|U$l>)=93x3;9o%>Vf5)>R|UMr{8wofS4IolYo+<| z$ns=tb1^qP7CLt@bmivU+Fsw~>%$kX3~lUm6?$x4L;hgKR2Ymcotu0f-V9kt+x< z>s`vi*hd@GRbw4G$>ouJC~X6=E#=|&qznonkp>zGi*T~-^a)0tB4VtOwZF%zWokLF z{XyQS&{7=&$|7piUwo^Gp<>pv8ya}cYy^i5reP3G67c@A=G5sn!g0ds;|(WjT2Es# z2u@lfwXv35kMQ(kgcI=85~AOna3eD580kIOTVbSSa0t;|Ss3xI51Q|8L_fJ&czC1x z?snqCv-z6`-5=bW|NQOc>C1!X?r-1!{*&3O3v<^NZ+vrUdAs-Fy^T+=Ogz5P|K>*j zyUV2~`_a#K0-vsW9<01zov~nV^?J?ma>e#?$%^%6*#`W5w_tfQXS#VV zclqkT;6}Ev(*yo(X0|)q6Q3RLet359_V&QV{mGTxNjM`pGS-z)wQ0{$@JXT zNbhV#8#Zt)0&kBW8E5j4!_}L04HoSK`38-EVpFvmB-nJK{%x}gNEQKRvYLbijX}I! z+K?tTngFXA_JHtwLx&CBv*>cy!e{&8>$6+0@01qHLV0@=;V+dY*11o1KKkwb>CN7D z_Nh?866|q>#>1_OW~q(}Uw4&(Dd5$i;!p_)CMy@@Nf_Vt_PFofoPPf0UO8_VnoGk< z2#j}QuOB&vh%byzWuY5tpxRP0QTbA&?Hy(=*T}{r?0Tw1 zeRf@^j3hI#F`EPa+A@Yf*=vdEVVsD*ZgIK*{6+oSnX{2Y8d1Ro^H|8tfxpP0`w z5wxt`I6ME*Ap(^~F0MxV)6f3!?BnkqKL69Va6IPA$WZnr@~(G(|8nBW_Wb3oSa)1y z;Oq4rMgv!CU}}sEI(nLaFgQue0l`!~nHngA- z3cxaPg>DHb&AOnDZ|wk=d+cxqI&PS6eDv!t%BzDLAMBlf^YQ98*DaG7rdKZWD0zBb z*K$7ye&@cv1TWvgvm*$W1-(<}7F)yW@%8?1|Muy}PjCJHAHQ4NAMGEFqXLS1rN~@> zp9X*ck0ApU_=|;OzqTFd?1#68o`zLb?`p^%40F}(DAOV~4s=O)6052z($lKTSbZj9 zW}%&n7h5Gw@aVwT!lnbR(O^eIZ4`EQ0(yG7Y~4l6K-L(wb8#McK*g*aoWUV&#@UKJ z4sS}O3yTwzvE)*|xHqip_a?Uo_FrBVMP#QKr)oPIkix02cpN=0o`nGu(MC=^%OOB4 zGR&@j_s>6k^x&f3BiFJ|t2w7l!bXR@RmD4Pl{cH@O;?U$g?CKWs# zStlpsU}JEccXg(~Gnch=BeKj$4e3Y`CmT)aQb8B8GlSZ;jDeC?wkG7nlB@G@x%lkM z!|#84fA7*HtS0-T%BX>c*Wf%MeVapCXP2Bw*=bP+@*;_0bh+d5vrEN|sT@Y_QHN-G zI$6#c%UMfrmv0Igo$~|TU5RM8YEPX`*|v8kRyT&mr}Bl0cVH}08VF9L^=UKHr)bT% z1%-@WW}pboG-W^_&zMq6T}apRg9EcZfRC2cDVy1wnY_Czj2KF@6-&sVKp+)vi6u8? zXX>cdm^Pzt<1hR2{qXz{(2Btz71Y_gc!X`?r3N)agVT3n@SSLYZS|h6^I*^3% z$khHYq8_^^{L8z!iN)a7x#Iri{{1V1cX#5ST`1sjp;tXo*3OLt`zt=!bQ}D91x!&Y zJ}5E_4lPH-lsQ!}p7N)ZL*wD8vB>^v_wHI{cqDq`v%Qh^9!XethFj%Wl9;V6tu=^c z>Et!5l(hBb^zK$guW2W>z2}ERj+|EPiKL1idsOR5nxX5b3P~`5$3`7k35pa`*eo-1 z(|tj{i4D3=ZZ2P3?WUMnprVn5?bupC=3od}(X7VE@-)4b-a$nO-TRFv>xi`tqIa)IzS#TbLeHa}__KrTyQ|&b z-{?X8`^Adq0f6;v?5}Q=-yLM1Ecu?!yT9E}Kix~h*!i0!@5_15%Vq!5dFPWk2T=Ic zvg-x<$$->#*W)EC02=GXy6fAs!M8hp9K71}yjZlL@_oJHc(LdJYCm6ezgY4-TkyPD z4*qbt@B4=v51wC`y}ugU?S=3mGZebH-aB6Q_Vk63wwasn%CA(yqcKy?=o$(;D_+>* zl*iJE-r&UkL}HVh)RCXse0 z*0Y5=1{R4|Bhu4Bq_l?RkPCsei%nN~Bx*03*&&f*DqrLq*{z7VI6s@vw@&!r+3ntDe#{D1zJ^f29d^Wqwy#Zo*P0&DDJsx zjy`Fh`)FT~w6tp2$T~?5r7nMS>#zTxzyIz(zd3g}4^$QKTc($Lrmt>ad;C#hG%t|R ztyZzs!dEETogQ(%GwjTA;Ll8>02W{@_q5HiT) zRWlaJ9gSp33tdI7WuC5~*ASql?`$Lp2&%Xal3Qfl>oR5tPAM810fZA37YjCDEuEwz zQ82hzN8pPq5x&qMKLdH;|AR%Bw&5ZbY3SI`7+m7wa3nVt11HKHP=G5kdv2;YR|NIc zns=b9&^=c%C(*O=ASq9kGA-QQdh<^|EZy8%xVGN2KXLZit-w+j%D@YsUo1@E6X`vC zdH3VL{pQN6JBVVmL+sfXv;>tVkF+wH+&rAQ`T6-@|LNT)Z$G&F+5Xu}GjP6wZxwpZ zsCfatN9*6fSKW35zL4u;;rIxGs|ag@Qzf(7n*RUdFJ1<8#w!8DH~{Kl+6y3dY1;AP zsIw#D>_G9`*JT^%aiRF_0rM6Wv5}5I2S70J_h?KEc}}ikH-*H(0q=$9*A_q9$sLZ3 zeX`YcVZ_qw`UUyDUrjlw#osu^M^EU&B;tS~$t9fO+<_Hx1udNws`08hIe3*h?`{yGH> zwvJlVyl!EWUrG$hNpW3UMAaJ8v{ltc*oVkk0@4=PZ56ycfG;38VWESU1zt1?=Y*M+ z*8g}~Cp#7tD@p6C9w>2e_& z3Rp{B{_aX>=j_D(-c(N|xV=5RFjw@!;8RUPjgLkL{zg!u=?qlpj>BD+>_RCzks|Au z2x>>M0PopQZxrFt&cOuJEQt3f;pB#94yD8$~xq< zU=CB88=2HLVtXTmGhi=!QjX$K((G5#sVz`IXo4oGTj`7%q0(()oFZ^f1AJkB0VkYR zat-1IQS^c6i!3&!SA}|+E$24Tn%meUl7Jc?N)K#~p8arre6xFeIkmErTiZxpzSw*5 zeC6`RzTHvN=8zU^V^Fs~Y#l8cLUyi2&lsK0^e*NxC~Ohpy3>MRt@jzi1IgLd(%@)# zWH>Z8mFeyAMiTnX^Hbv+y%^kpN5R&hdT(lJKZET$z*nWB6!Y5g(IAL$P@YY(`)R`EV@&6#isCd;4nt<$JS-pRZl|di~(R z+Vv-wZ+(5~?)|eLT^YZ(k$QDdczvPp9q{*B&v%!KFLvTjP||J&-|WV!F3n3mpzUui z6y97cpfCMwJ@jh9`(nul41Kmxt#eU}-mE%+zZmkq+4cc&vEJXJCOH*}rdi0%9YlD`Bsz+h%IK+tW<9)q} z$D*G$!015B09gW`A6zCGJ8x^LknVRIV=|+Kj)~#clZ1{&I0zA>ZRmUOBvkNzF<8O&ATf{tP{MZt z+E@^qF@2_EtR`-0W}YGO8W@t+W)`BmPRVUt#I;DwOhmHkLTVW8MhX_5jnxs8DSGVU zQZ*Hh=aa#53SQqdHE0jYNO!;r<%yc!*h#?ehyY6XRZ0R%UCIodT@!^+Ppqw`0Jqj+ zw~TCSLOYnlZR)HQ{-x!GZYT|1t+aeh0SSLn(quF*H4)=Ff80No%QwnMi3Xz zFdA_`ap(Mi;HpI}!aAw-pgm*qi^mpbJy?`raUd*-%5TAD2DXPX4c%nrEAFT z{>no4Bz%ez2C(erKHvM~kB^4WPbwp-)JUvvCJ$E@yaU0Au6sNc?DxUWaqjlw=x+aq z4-R&=`%&-$dH-Ymd-P9~u7Fg4=}-6zz^wxDk6s+r?zFlc&-_&X;`Mmu=t(@{q z0q8wIK$O5<69f1=(Cz3i+fi`kgHnJmdfGTYs%D(WgElO_qhH|n3lX7v@8vc0c?Pe| zod4ld_hz?t#5;ato^Iy6&u@egoNXep_xRHI;i%RoLJz-DN8_Y)fyKN!sNk~CXgT!( z55EYrDS5L-R0sUE$s66u=CHmUfQz9mkT(E&ww#C+)=&~gCY)KpVFrx~C=6r-3LgP6 z{?zbu_K2HM0%J5BRJ4H$jg>J|lZN(`k(@Qt0l{Gf5fF@ie%`}P+UPkq2N0aLvqD<3 zg>qU)&93+wGVYN=?2BL_uAQDerG zwN+O8;P1*XcDO2`=vY?hR-#Q>WkZ>T(CmXWGJ9)1z1{~!c@#!`ax&UziQd@S#TB@- zV%te-s%vj+I8%QNj+CHU>0AnD#L%gvQ`#F$F1a(d!pkEDVf>vw3j72|Ql205)|x?!wye z*nBs1{YVr=Cd(Pp$rG)|;2n+O)bZ9+Eme=KO8Pw6@ef?bF(On~Pz0m-cl0!P~k-Em|vl^8GN zmWN_vMc_DO&KgClM^S%a)c#~Q{q;^929J-hsh+p2zd}Mx9je2H{8JAR~tSokespJYz5wK2VZac@%UoH`Et{RTKMUz z`{icf^-dJv{&Fk&>+R%I45`=BBh%s0gF(37O`RKE-5(p=8NwW-xH%eI>^D_nFu3-2 zhtM$b6PItrR^bjB-ob%WXA(wnm6 zLz=^p*!|_olUu9Xdqc$`zg7o)Vf9TV&1HXbwI5#e;qCt1h4Jim&oug1C6g_x^rbZ2 zLq2#K=&~C3L|j&|pO#awapjtLFm1-?gwS>pAA9I-eopuWxD6PufZ-3aJp@M#ArWfd zCdw&>jD&tEv7^3)Tie1r1NxsWuE~vtwFR3#q%=7@2PPt+0jI9lsvGfJrxNW3mbu`x zmE7Q%)iG-zVnR+I2n@QY-c@u%FHBX@ngq>Y7n@TSlC1p{;l%OUU!FYk^QPw0=<^^3 z5!apGslEA!uR#BpI6wR7?_L}}y@lCda441^O{09qdDM1cC#O-tYP9l+T6QB0a-hX? zW}NP%-4!)TU{x)rTFjjSelwp_Z#Hl}ZW+wzc%98AGhZZVW6)~AW&|lqqGHN4T%-U) zG=W_%417qmdKiy1b81^*K8Gf=sO1d#ecV7Axph*v*j{u>!zxdI5F|!rSlujY<`_Dm zZibsBEWF?}0;ew&%g|zA+l;pq5PXEccoPs4+zG{*jMO1$?%*}r?R7IgK8Fp}%ro%rDGXMLNa!LlEpy=qZ> zb@}k#IcS&Q4jo)BZ$K)4XJziziYl&kmK=Mx*8Px-*+fn=Pokx=O$=qpH1WaG>W9l4 zmnZG+PSCCb1}cWXc*OCM?Q`{+ADhp(tN+x0K7v#rFG^aV>Ji8Wv=l7ZTj6E+k}5#| z*sMMRYkUc4!xmXHUXPrkq)*gWw4hB2!ZZ5VsEhGDzOah&_*xAaS{|5TS~P7S39s%A zMu+^okR-5PN?e|tc(|S1D6`x`j2$~th8i=I>g_akSu{>DTxbx;C@5J>1AcUD%nFK= zODGhLX#P0NG@G{7svv-jkhU@6hIYU%z}K&6L(L2D#R0TYNfQf|FV+$A9@W1`5S%fy zV_GVPq*&l8gQ=CVu&@etCLkCK(3v(;tL^9?@wedSf(4y(vWuRMoRfnS0_kAQ0jSO3 zl|WGj{|4E^Ek4R=t7m;j13@|faD4O2-0_oJ3ogN79XwtW3Dfgc=e5ktX5 zzZCq9P{C)3Td=z}cDa$zy>(|h)E9?7vjD{;ip568A&Wv|w*oLm~PDQ`nt=sL@o*U3@lq4$!@p_MX zv0J~~YXR}BcQ|^Ca*U?u!u=BBEQ?DHS_@y$itT!~-F`r6b%=_SVU3U9 zX`r@pPq*_P~gQC~~R{DF;TSh)s+Q7T_X?jG1B2kNXB;oKqHnI0UR^4@M(okF0~PVx_29dW(3@2+ z@b}$@2l)FIZRa)5^HulLWhWL6j)1uO_LqhO zPIsqPj|^ExQ`39ys730L!GEA@8?hIIy-VfEwVudCLg?!3(6_7IJY7VNe>z6vC)G5V zxZ=}(igXOQ*oX{N$Eh+ZTDwq`Bli&aTU&Rmk#GuegxLDRX03c>e(C-`L=dILZa`0I zb1*ZV2i+RYF+>j&ntld@b3H=PxJ?d0s|hZzDu%_2Er-RQwi=ugsHI>4i%Urqy zg<>M+=@Jdy;Z>j=-N7TUghajqcJa;dTCXRbI5OdZ4iOfV1X>MSO#}Fzq8$eyg1QXV z1JwF76$Q6?m_4?t$Sf-lWOAuj3K<%ja%>G331|(hM%<%nC})7bP$|M*tgh`;J?Ru8 zP>C#@q+O!tD&!Qqg|AbPt@>(PL!%~36fFiTiz{toN{Qa03k^NCjSparOlI6Y;nZki zU~32#A`7=SMla3#hm$v+e{|>7C!f9iaBOF!Z+qzDw;zA|cQ3yGhc{#JES*jprW4ui ze!7J%@=GOQMSL{2yf$DIkszG1Sa{j7$i&s@&4)WZ>qW>X!|EK`d=LX+soh}ZDywY;_j>ghF7VG z9Cja|KcO-O^y6Ej5JTOKPPpFyaBoA<18NO_TAQ2C^k11;czk~Ji=EEA9yAHKZR9Ra zXD?4X=900cEJH)%2c)8cxp;9B%A@;FuKNsZUq_R}Ml%~pnW!Y`2dk6_OA8SPbT%usG5qh7Y$ongLyl<=;9OruMS4mLaE}f zm5wSnq-e%CII1QVJnZWCvNHk1cm)39BxxHng)y-PY9kUR%fRK7iI%}KP|9{z&Pb^^ zIR#7sWP~`VP~6igv<_s=ZfVoe3>x5@FjK+l!kJNG$6@9vYr(I89|<#%0(?h|%(RJ> zv2q9F#-W_Ml5(UY)<$n93J13nZ(p>yiY{%JIbcAHCP-5NmtZ$C;~koeW#;xqX{Lz# zi8W!h#ViO2fYl7PosbR@v6lwdl2Wg=tE767-l0a0Hn)?6ykLKSN>d7qU*DLyyoxR~ zjPle;n^eO`GB5tulMPs+4nQrLO|rX;`mh0tA=JNUKBFHCq0Qo@)wxT{cVFDyy0$Pj z9p9Lb?v6Xp_8Inys_TQ+-Lh`8s66P`@Aasca>9`quP@R$mRIEh%D#ap(oZna*0>be zqEA?jA8izg+NE+Tg1X?69m$%fAVPt=Qm=1rrz<<;hRRrAAk!uFavd?1Q4IE(r8*j< zM%cYWzzF7;$|S^{2je7cJn*|WLZ}F?CYJyupaMOulpS6%k=X(w+fY70&jp^>)pN`R`Hv3;YG!>LoZ@E1sVg zc+pQ5ozFI^>*<>F@tXU^R`Bh9;s}4=9_F81>A88aZ(%)u_`%BR`N@sL$%(~MY6gyW zGqRM+H&uzROgJaIRh6i^HySC2ux<0_y(DovQmfqkQCOsg=DOr5y%;@;`5w>00OS^& zjH_^d4ym{;3KrceF?0uGOTCcdnxWcG+F>y|yjGc5>ltDjgcB>SC#h};*FQl$-6F$H$JW~&#g@eVBvok;Z%in$WtFIQ%E%a_9 z?KB|oXwk763><<>PEoTU(4eTqq(as)I+5)i%f!08=CB4fkI|Ax#;z6d>eV{B-YJrr zI5Is4Rj^7)S6T#Uh+#p#hphzkXfXCw zkac1rJmf5xP@9+zD;u^9R<8_lGqm)VZ>&Oh39qNvY$3H!0m$y$J6l@mMF`aG?>@cv z{g->6U4r?>-~aO;Hg2w+e|YiXcb~of-8Wyo_z2vsu8scm!H8oxMAOsxJ~1mG35>-c zj_{~iK@G#Irgn;v_9Dp)`{gEzL{#TS2hz;=NdoLQLi0<7DVF0$`~`YqRWTPd=^xSd z|Bt^%;EUEV*j51RqhcAjjQKApu6RBE3y&D`VrmTWQ7$Y8+c^RO4ibS4sDG>Yi*g$r zFn}*s%ErXd6AfDw$bOGt`P}Hzou$j)-d+CHE!Bum)$NLJ4<;{6h_lKQ22RfSxwBXDu|~FX~@F zFc3EHW>s6nR!Y{vLZcXH3pN){i}`Ot(}opOwU!+m(6Io%0Of+Qy=-OV^zA8a^}li^ z8VK0V&RT%)5&l+x20iH~{0;xu0LKr5N<3zuVS(j^Vm6|sdKJW?U(u7amC}x`LNK2X z_YW2>URju!Nc-Jl#6)(5HI~l$q?Vr3v+(8BOe+`HWunJG>W~s6Zb8>b5S)Cro|&J_ zL4OD1n)%BsuoH)UF|1%1GCHI~Z6eZf@+pWY5xzEdFpc^YHa^e~LMQ}D5h9HmfAp}z z90vk_NC4m=2{=X;815|;N(1yqY`bLm`ug~dZN5hX`GCNss%%fG9V$36nv(9~!cbzg z3@79kS~HVP6@%P1HJl$ZZ6XOaEgVcrazSCjCy3aEp`eB?BytptuD-;`a7wNs$Finkm!HY0L#!3v zrO}b_=x8XHGo&+`o?&;Q%cOR3RW7c)S{Bg@1xc}Gg6J79G0G(FFre8e14dFwx52olR)8&Qu@Va^)D9cU*InWyQqJ^+w=f`Ax#1V;{faJR_NQE2p*rWJJ5oDw(59{x_I4( z{`1?j@z*~PXow4t*>QBuJtp>#GYv@9gJNo4I} zDM_Ve@@2Jt7dsJ^4KJp0L*7VI1-Dp7Rx9T+NFT1|_{@+Qjqf*|K>8T$I9l6knp)n+MGEQ# zg-2Swf92A{+n+tY|K+m>Ti5sQz5QzT{Mw~YuEF~F*2nui;xP-S$t7)cbH_$8~G_V^K zZpBgaty9Ot)*1sch`AtagrNr>+gOc6W&_>G7NW}G%jh|tW!p|L6_(Nau$ zs!YcOPqH+f$N7;g0QdX8gQ?2icG`ziQW&;Ik<51-%OzPGb* zZSm$;mmfa4HNVvJ>UUqk&_+_SI(xkepH!1JXnNfTFK-2MHmjT#P*6NDjnp$878d42 zCV30Qtsx}|Xbb&ORRWA6^hYcPEaDk}>CviU=#SPJc&yg8I?7T18Gs8=#x3Lsg7LB= zuto_Cw8cNsdBzzapTP_8B&NOas6-3eV`1W+@6nS2W~v*Zz(#U)foW_3{!)Qf5Co0K zHGmi`zc%0(&+ZI_27Q6c!^ulyQ=guV>U`rw42HESj3ETn>sjH(k@i9!`v=@HfWBn==iV^vGke;@v$ zVg&>r;V-;9fWOtTucjU6%-U&rCmpNcpry^|1_OU7z~6|v1uKc1L?=CCqol1Az;xEe z2qG$$=`idoF}}}vI!XZ{0+`Uf?}m{n2v%vS8KsT2ZC=WvqI!v$l`_n+YN)K;T)>z&yEW}s9RPnC4_om=kO zoF)ipYKMU%~yJjE9(6L!(3k89~YHV8u+fr5P%g>Wixg*zg4DW5BDbqx|gotB%{+ zDyFw1u~EqSOTzo`*+U-dNeqrTt)P(rf2$_9tfn@YDe3rppI#EPiV`+>42pBkp9@>j zhHapnf=IcE{=Qg68lMQxO?lQ9d|zGfdUz0jeh>p2>fM$PsQ2NF8R+@LtF;&R`k!6N zKUniVIU9vb^Y1^O{r1zTcOQ&l{p!Q$~?)K1|8$EBXc4MK5jn4D4l>qABH`mH2 zt6!Z>ezz4v|M}&z7Yp-W;4k=B0N)?>Lf`F10lSa`19Pz;4gTRU{r!FdK zZ#IF;(RW+1kI%;UH^T!{uEFKx`r+u_g_)g8vwgE!n8tLCB-1@ne<9?rB#^P_M3(Vd zFWawF6b;-aJlC_q%ubSXTx3~|y%QivkN^mP=)L#e zdj|-xfW7zLs|wXEOLCKaWLvUi_2znNk}t`Av)^uh-u*B3f{=JKJM+vtFF|w?xSspI zuQIS0U%k3Cd3g=VYPP97H*P~Yj3~4=c@qPz4xdQgYXcmgU{?v<;tmaCVal|<)Y7@?NE&;R922H3@|;=f6A4vhk*ryyV}b<5z(5P` z;?xT8lwi`1kId=vcWcYvM-7MuDUxsrlyX>YV38S>ZH&t1mNRYG@729~y5#Rz+*+Qn zQLbuhXO<)UOCxWL8;D2q&Xsv*bijlLI6q=RxHJnwT$(8w~ z&YZ1*T`Mv00HcU2BJvtY5)#_ZU_oOL49x{ZN$rYuP}g90iMpQ1YJ~crUEBs6led-v zrP$I`z_t#X_l6HD2_Iq!sAXscBRojQL5h8?Sw>R8`aoS^WKji;kUPN}2SG*G-`wdw zoWMWWxjTpJH#g_6tqvSa;PTIY{&w!l+WeKZ++0QylwY`iDLEPjl`9xfU%0*&9}Y^h zCQujDK51$x%k4A_-(2aQN}3fkx1b3SY!eZ*DCML?SWK8<=??<1s1AK#U@od);4e_P zpo)bx#9QUjZ}n^ue1WG${DrFq@D~@N|6E*{;o`S|U683DX~7ZaxUc}e;zl4c*g<|X zBWPoRh=t5S;IB>j_9$;C;xB@39kRmYbTXz0i0VRk0=!x=t3qR>gUrC2@eSVHKL7Kb zu{(SI3zOrIE?@YkyK~>}O?-FWv6c~c>LdX%O;8JeMTGFWc=aA`DON;LAC}j~)r~;j zE?Zk%+X#rXvdfAPY@nY4{^Al$RR4ec=l`z-joe-y0c~EmQ2G^(|B1hPLPXQ}8~$P@ z>k?LB;RN6t(iE*HlnjDFugK9JUh_a?Nmre@sKi~GRZkrQn1K`4RYFPyuB&Eu(QVmJu-OI z8fJyb)-kZ#3uoYgy-|5sV@_F;;|XNr%B^BV+JQFQz-?lJv>Z3*mj|%52DO7JX+_(o zf>HsONLXrcRUA-@Q56=#@@kHi)g3RG&(xi2=TkT$MtwsWhQf_?Cy{c3WVClHkFf;p zt>ikfjEkt^f2=qraA|A^mb$*@naTfMG3UnjTh@FF3bYgdJAI@D| zhSoUM>l+#N9jwF`dz6c5{%*H)GtJ-WlFo&h3rWFTRxzAb!Iu(w&9QjKOiw$`WX-}wMSU1B*?$%eaiIi&*Dg<_|Ws-d*%S^BJ# zX(@Qq!i+t-Go~AjiM(P(P!7wT&dGRsz}=m*TDLr3w}OFuXIB5?wcM{iZ{NL*3Y> z!^_<$itnFIJh`0v;pV{03+bm@K~S(jghuoE-a+*Ky7%#dIFa|_&gk?I7a0EftZlB8{t|+@Z z?j4OQB8I8ev?HnW55*}KWt&}120Ladu1RaExuyCZgJ#H)y*x?s@!GtC>{dVBz?{gj zu51JjmLuqR=tD|47n#E*k(^0kHe@=zN-34mT*_%F<&a8vt>v`(<2Gi=*K6JP4~8%A z4Ga!BLjjRcLuxm-$`$n-)+r&U#BQRVyD+|WdD78m@y~|jNryD&Q1v<*q>Zf|2ditq93keG0~@q^Pf$55$(r-yB7L)CGlfwT*o$n3ht_A+SJnwjMkc2ygzlE-S` zFzcwTC5?6Ofmupucvmh3k+@VKM}7@)GR(O&Z9TgliuCBTDPx_2#emOD(ugfzn~ni1 ziE?Tggy)&D1Z-EC(stl4?BD8Op*4%d}SXFHmJRJvRKKN`!78YJLd;{=N#j%-K%Ht5FoJNy?;1m;MUeWM+ch|WQhP+ko zmPE&*;mLSrxjVIxUAnfieq$Xm3WIPTiW?wDa`(DN_QqsU)zG;KN~cbk)=cjW2ZC}i z@!V0lf6OJyDtQq_@AiNtXO%|e#$or=wb{S@$LlMX=TV%ZTm@(r3)SCBTC{wN%A-OP z7!z1^3xHV4I0JVksDO)HXtS`^B&fj=U1FTTvqHlv!xixTk4tbh9I;S~VFh$;XxQUd zxZJ?2!e|&RXkavwk5F;LE**ngHLxeUqq8 z$E(658h8}8&}=4pV!$zRacuSaY;Qkw>_nZDKY3}Il~g2GQ+J+RnH~?J;x6nfxK-c= zqZ)OKs!^Fn)J<_+OF~bMX`6A5J~K+}Vuh<`mB2cqs5!#1*n-Bdu!@anD1wWHZSmeP z?JeF3?iQ;EyEtM5Y~z;MdF40R)7Zc|XYBAVWeIT}=G^%SX=jO;~kN|o(2 z`eW+UWY{+7RCJrvc`GJpnzR8P&VzG(a9NLxB_UFPUmtje<@EAaO-GZITF$HoWw((> zf`y~VB8Ejd*DUn*2HPZ5*vtw{LVQmma-~2)L<70@bb0kj5~ZP?-HPB^NN#b&7Wc!7 zW2hWKF=9(tO;i%Gja1oCT?ZRoCJEuTO0%3HY{wWBSw9p`tI{b~Iu$i-brsFkECmKOinV^paFjWomgSRbCmO#dF0%F@C6FlE z+dJwJh=#r*i%(R+L)#;@xWooEXLT~M+^yfvh|Zk(ND?Oalan9?pFLD4|$sHKWY4IS0^5<5}TLYAsP6)-FsO1!`l5XO2EF!e8(E}_w{Z3WMJGBj`j6nk& zIsTDS_CBZK10JDLO+VdKP7+WXIppE3X&Cu7$!Qb=7b`Rs5xRJ*hoc`~pS!Y=y0YN> zb}#T?-*acx_U(@M=~4Xdy5ox_^Bu(OE|`A3(f#bv?A=>kcP}LhNV*$>^7rXc=hMr% zXJ3roznuNv4wMU>lbFx%hmP7)Y(9IwqKcW8hgU_u{0}T z(u_pSvt8mYuPo(q_QrHkdvvrDZoLAG8YfdEGmi-Eo0|Q8do8$az-t6*^rciY5BHuC*G6`bCi=_NvZ zzX|J=wg0f>5kA=I|7t&fc{4pX;aXZwKd)$4;L7$Eu3s^>rm>rN>U5dI$f0 z7(kz@00ZFzOius!Z$G~NpFjTb|M}NXUffyQozyBBO?Ah}EoWFwCDfW@a%vUmVCwc# z_$MfsB?@+lm{FqOR042uqU2V=3lW4LATr8Kx2zTTt6)@v^#nf?rC){&sSZ0&i5R=2 z-Zd3>OvS`0gQnLhMAU^#jC^Orbn5%P2oBCHcKh?b>bBA|Iah-%)QfUy86>-CPDnC>9_X>E!5afLsU9WS0apxTZ+2 zJ-yWnV&vG)NZ-c5^39FhT7Kc9)yv;q-TQ104wL7;y$mT9@*q%gCuh=3JI6Wf*N^)o zF$IKjaz(*TaCANq9C8}^%ozAarsA8QY;|qtL52^{MAUXREPnyJ0N{&Ut0_!iUvg@L~y3`5AHQ8kH- zZRiTxlw@h!DGsQ@ZcguE|FuU)$SgpNf=}HFZZpWnP|g++6A~eS9bgW0WgG#Nz*)>> zi`pUsyA%jptb75!zu_-_i>m>J@muJ8f#b#U7NCjy!NSZJcZ(AMZgJr{cq}aRrGdY2 z!7Ab}Zf;?fA`v(!t;X_-Dt+QAJQFNj8F__4HFQihQ6(`Xtq1=~M?0aUp2Qn#m)8^s z&!R$KI<6!Y(A(3F zaz;%xj|igxL>(b;9RGO8S-=9mNRcd@^Fn+o^QfSLLHL5gr+L5O!zNxcQ~+?a!-Tg$ zL?l+g{257SXDUA=wAB+S4W-~uwZK!c0KSEeG!*j!I)z0g)7xsBU_@C*<+cHW+t_4s zM>7_#j0<531hcF&jivQ80!PJ%`!QS1%8qBwf3mxKesXNk4sO*{gu9zlUhX&V#%0rK z_QsIDCn7kz(?33yFnZ-ssc1u*&i)Y6SQr8l0)q7pac(d?vDD*^>JZ~NJ{p-BbikN- zCc<4!i1xen^I=g>LNziKa&{TGPIfh;92^*xRS0Sa5#ZU*k{M$l*e{-c2>HwItd9C>`P`{~7=2Zxy_N8Jz4XP<0@A8&;U zQ45QfCx?+&=hBasgZHQ1&>!8KF`}?77*Q7ScV7Fa1ONZLJM&~O0tNAlz0eaVjNV#M z7CF)Y+(&ap)W5)AoCAwrtk@B{1oP+Ee7yhK(%_ZVfphZ%d(*kik?8(>WOsV#qg{1h z#5j`lED!LzT(;Fd(`cIE(Nys%mTb`38+8pQg$Z*+OS{>xcQdNk8Jl*n&D4V&iO#o~*jB7cMu^ z)t#=sxtOQNrU4l&Z4~*XWJL>vEwE=%M^q#eo#7Wt6IylBfb5tL>OVj(2`0Zh5xqgx zTE?y}p_Z_<^g2pu1GNnOYCv!cvkJXv8moaXZWV|~Y7IrD#bEjj+-SitIoq%MY~K0F zdT4gs>CBlWX`86W)?(+>h?}7HEpIDrK!!+rbya(HAv37{6vjg^R|hMyp{W8y>*FW> z;mqlGPr=r-^caW)ScRy~##87~FMqU^-5CD%-(TK*@!9h~KJW)L1p^H!MaF1g5l_n~ zm5}LZ8L$VeRI|&~ymEO*8FVhN8pcwv%5e_aDJGRhPCW*K3Tl~N*u-H~tDL-vi!;3! zChLuKvV)6V2geT$EmaU!!db=G@1favvXsd@fH-3}((RWuaeS7KZquWRKuVNV2DkW2u zZP1=eLki4x)p2EP(A_s0l*>rDtYzzPY;wDA_2c==_b)+q6c`UCH@dI9xq0dSd6H@+{zr&=b;%^Pv4%{G% zwh};0fEQ}aVxbC@1Y%;Lu*F~(M}RC$BZ06O`xb`3a)M9RSnT)W1V7^3&acAF0hEAI z++nd|MF|Y#EuI62anHB{kUedp09E69l-mI4h9dsrSKwu##T}H@qVfd+8+V8+fA* zF`C3WiC8D2@eq7Z0==0n5f3|Bp zBQ|k!8{4r!YV99=K8sVb>Y(leK`2gQTErdvCyJ4>EtTmFZ; z{`*^=rw5_0S8V7!BmVEZb?0BM<$icL`|y+A2iH13-|!&1_v!ic57&DC_3ODO*9M;6 z7=H8F)V)i+_l~;n9;6>#=zen4177r#!^HE$D0EDBrgYD@BR`$*zPI52Zr+X=F51g5 znS8opL;d@7+4#e@^Do!)7!X6g^xcyE`KIsHmhZ)y>(N31c>%kqf(v4$1#@w|Ty=bU zdtvL!gn8H%+8P-9WN+l!R_5${;_RGazDqKeaIOz0&&`ImMgYE?E~j`X#15IM`0CV) zgg$+Xmgk$#=dP~fntqU*RtA+3OS!16OxVhC%N$*f<)hi7gPz^3^vzFZchB}@`*ovJ zF4&W9Y$k^%z3GgmJ7?_7I~|=CN6v}4p+d`(XghQUuGNCzqBE5Zzr%P}(E7nvm+i`a z*H}ghZ_oRe2VZ=#v@+q1ClvThAyQ2wuCb}=dwtCPDffl-)WP1s-r32%*<@tI?;3Q= zLege&1NKOn?Yw(4ryKSvdu+0_ktj!By9%i#aB8Y;slwbRI1+~3hAwVKn}yU~3Fb2j zVF-EHf+m13oYurBB#kt=mMB)&xTNHMC-2r=@aC-N>PmEI*acH@I1Z==JT$iumb{g) z_-H;=?9KkJ^dC-?y$5AIiCT}1B32u#S*+n>RD|NUyzB$ahA{cX6c{=nP#Wlh*7Gkv zPwtHB`aH6*#u(P94Q!pZBj{6_#8eTbO4?STrdFW-g@quDfV6^2v@v0I2-w9D3n={7 z_^4LXUg4IssM;%J9W_z~8D@`|#WUh6alcF2=TvstAm){Zl$aMIfC*9WXr5aJ10^B? z+035#cw_Y9yf~o5LfUC?Dw$pH$5=Tu9)fF-)2Jwv_~xC*TYd?s%Vj0JJM6p z^Pg^+l3Kn`7?_KW9gTZ)29Udu>4TaV$cy^7IJdYS~5Do znCBL|*0|Mwzu|8`7EtmnK^iBxGKRcZm_j0tzNkgQg+P2PJP@vlRV=-6eVe!iLS4Ry zz!bye+?pQ_%fu}lYK4?`8uyQhB%TlY&(I?Sd_CIc0Jj7jDwn3wC9g%P7!p(is^qLQ z0)7pfb{d&VAQ1tfBJi{nRKd0a;0w?MO8&NrKwKnN72C_eU-X|*_75^M2!sPDa#fA^ z5qF5|1KIH?Ar;9h#}1(u`0M6Xfd33nEre1P_BNslr??VNK8P3l_L?zcd)mo~Sy|W@ z#Z1(+jc(?ZC(Mk6URQ5Go$^TMM484fUASDYbtwVanN52|d*P!TAiN)?&E9%w;>5dR!@I zxHp8vJ*JK$a4GbiF7H@M7%}keQnp!WO4zW_lt#J%KnhyCV*Us=+f_~FAC$dEpf@(N zNcGe@%%OzPu(dZZq#c%!-QcydWC9A032zOFUg}Q;0KV-4x;^B;i8WwrW)m9Q>wv#< zlLEhm4KgSzu7nNd1_KiTpP%bBw~Z#G<01Y+M6{RF&i5$SCp|hn87Us_9KL~1>5c2_xw+2#at~OVdq`aj}?bU?G z(*B8zYbHx_ONl-?6WQgxA@yJ!QUqDXHFUI!-zH|er;e6=gGi#4LJd8&JG6Z;czw6) z%k|jP?bzeJ01DoRn{L4Fw=1>>s}95!A)n}%hqFI@Gx6kR&z+sX!}H09z}BPAUvCcn zcw_R_$CH1)xB2roYj3_=^**Pe>(l@LeDpI zRs{RrpDnbPQOqLJ=+Tnl(W>dqVdB|#=ssc^=FHDFysx+Y;6DR@(QpR-0)=tq;yEC= zfWMdfzk9g7b$x8^(#Xa~i%VA*htExo-CWDwT=nb>4&B;H?v005`#keG9VQN|1LmoG zt5e1G>!9A^x)r(osm_bb(y`PsMiMIGK@l=e2N7>&hEHE{mvxthgy%zj-FLm#HeqqGkJ!pp+cpz;=Y-rd>Iv6rw({gbo3VYI(-J!y$dcdpg zcO%@PUQC2vlX*0#oCpb%T6s!O*3uyEqspiN1q@^xNtJTH93#=X_Hw{(b<>F|;)i8~ z53p()juTr-2+e08IX76?xxCdM6H0Y8;C8NO)%UmJUoLpQ+)ZpRM*}@(%Ya9gv&b_h zm@=`gJTz>f7Ch5<0(u;X0Sn3|tcEkN69?i;bV4G7P+IbSMfq`3b4_9LTlPL^OGsxp zQ+r%96+=hj;Qp1K)%?&(KGy3FMs%>W;se-;rxmnn)W604Gv>db(H8LqW&&8n5)btq zPV53ALfCZxUuHE_NHzrPj0HQA8r@XXI2G+W7())1CTU17=5D_E;_RdA74jC6gN_S`{^7@(U&^WP=DMhDRvN+(9!k5E!IHD_GQs&7ea^SF5RN2al)~Mz<7lw9B4#F#7dtBmlfCe4gxQ6>#;<9xt7>hsYB!XyqG}_rOu;LK9~Zznq^0OSh(76KwLypG@r51TgDOdU$mfcjutc^5-e!k9JOizE@cI#R^i9D zCRaED3ULp>+2RPectk-B2*v~9w?JE2mRMPA>2l^)f&f_zOlfh+$Cv0%2XU8o#o>0P(Vd;Rc>z$N+j36GIj>d|-+NGPYAx z9XHYYqw1cBZoJcVetj@#=Y!vlMsy+~cUqZ4Q=MneSJPMlW>nmbiGbEOlq^v;j^>uv`gt$v31-wC8G{b zuzrngC`#0`a|?Zm$t;REP>JXoRt=hGQW|_>Av*%K5`hasod5+d;Him4LUuN)<8~Pn z@!1G3V5#^>Yh_6JbO}#s({YqSrj(1^AD&tq%Ec?2!9{6qKa;kl!^%wig`cYT}v_?|iVZ1=%0cdmZExxANOo{B{iI;I>p(e2PP z3N$RtxGUI=NK8N`3u4n@k`D-mvo2drL#Q_>%7{A$OAUo>vxw9++c~t$ z-M79vJpb^@rJuj*KAdilwbdhl$){?Ov>^|onct#t$ltF#23JY!Owh(hZ0qmpj}zpy z^ya7vv*U=4)#W7Uc%qn19I>9H)nfiTyg8no>e~BwAGH9Sx|cuRJo@@*_v-xiTIP$h zeV?yKA8dJ0`QG1fJ=*qSeZS?ozYH%9+xOQx-+Vs!@M`AnLFC0p1)lTEOSzXvoj-px z@$2o`|9Exj|N8mbfBbU&&);smxHkIaeBZ+x{UB)FMTX$K<@*`a>&@`LeK!5ipU=M7 zkD>iv2e(MYxz8y=9Kf7lHIYJt31=s6b$ z!Nv10mTh;>#%>)(Z=Xv)xik0r(c#wFe9vOE`|Ma|yFWaYSiHJ?_|^HqP&7W1TfMpK z*q!c3J7pOg+RNhyV;AmS+5Yz0?3WkUH%2BF^GLTuE)Neb93i#H!H*7lrB?N`s|&!6p1^lGhf1##B4<|v<8z_Z zR1j{HeDI(9d|+$0$f*rT2uxYQh^A<%LKmhW1TrKtjCvxW1mr7va}6rrlMU~YnAJ)H zo6rJX(kW<=Kdk!4^4j;ys@@?qovN*SUm_+94>}JHa`|5QaG>q8RoCnDF+^iL+znh` z^(`;Bho)T^p-SRf_efY7)wL-oFmJ4Ds}O5BWO5BkKQOFn8%r_&Jzn-6^2NZ7MDrP| zuD%rYFZ$0Q3gtiCbfEDR;FVp)D%v0854OZluEFjK?Ftp z3;flKs(}mms>i|?coBl}<&STEHN6rrr)Sl&n@=j`WNSnz3d*1ujc*S~vu58+vcn^) z5;n$`atNn}FPUqhQWrfw+0&|O)z|Z@aOySfq=myvt|n!ku*7_P0)l-I#biG4XZ$U#PAfgD!P#l z0qVpCpHJ35pM^8I)+3 z#-z1iepN{RZ7c|ZB}AjB5ux)4>{GF;uyCT~)ykRWN>*iYK|h5{3UNZbS`ce-1%t4` zrEbH*&8;#Ljzzx?9I?=&z%zmE6-=Zd`Y_vhzPM&|F_Z0gsMXCfUKPL;{b%4Ws=Olp zI+cau7cFRrYTkTq4qOj5%wQ*g^vj8d0(Kxh z@GTLm2%`YOBL3ot#6T_cG**FRB`HXdz>>nk36Qsl#emKtwib(M-2AusFHV5AxLZIZ zj_6L~N1$^Ne=+|Bssev;lOp~ChymZYpS*{+)NNkvcP&G0>K8**ge&6-L;nkoH0odY zWnohU1yfjCxI^GC+SFEIHGEMt!Wz6wZfz?prh_VC#@ddeIACOqbh)-Cx<=Cu7)v5D zIO^pik`Eyl(XbS(=4{r0gj~2o!vP!Qv_jvT4+eEDq*(3(4IB4g=QdK|Wsw{8BnRB- zu>e6-pI*)_ezs#B4O5-s@M0dR2jD*wMXeoXVS~7pqDd5}j?LqaHUA+->iK?u`K<_-p{s=4)yLPd*&mHl02 zBqEKDIPD%TN8XG8K}6fjoQl+F8sDo!8)N8``|_dQrGAiI5iJTwJ_ISwT$tXtvAleF zc6xv4{O$FxU)-GA9gO82ogqmeAaaBx;hfnSRPhzm#7ImQHPH2JeZqo!D9C%oEpmq# zN$8+pB__JyY>Bwl_v?;9^f7lZd2oB{_IFnY*z=XAfXZzboOOY?j(#Qs{leV~!! zJGqoxid-kUn2J<2Sl7Zpo^9mgeTLO1Q9|*KB+zFTb-ROmTUCc4%)rIvmUmxi4NA+FB0(Va<*a@OQhu@Am@eMLz@z@A_X| zh`;!#>!&Y<9)Fbk>LBv`M(^{h-EXe;!1?*vxvpoI^8fUQ#UDSL`s+8#|Kq{NU;nW9 z%V*Pnd9?oW_Tb$$=hJo1kK4f?_TvBR&iw!V^zeUuI}e5xTF_7C%rAhdtJXJ%zDK*x zd(-A0b|SAf!Mrl#w*cRlJN_RJBfwvjy+B@^;8;Az@#&%wRrBk!{?~hfS9{@q`NQ0! zJM;G+@2^~)?qBZQyfnLXFfq2A@1E|=PUrephg^G8w)t#kCA)kyI`&=opVFI<6dZZhZaLut`2{7 zV{~WHGd^Jrb!kjtg(qz@M6_^I;j(K0c2YUP?qV4g4g1sKCugHC4kEvtOZ;${czCw+ z`eAlgr?E=E{ch_nWIuN==*syN~!`Go`HHpDZEM`9!IaO##z@RMOaZ zfqu(t>Jnu2Dgyu%)IU=^8HfL$z{ z19`!ME;OPWkgQ!=*ILS;RRDi29d#xSyrJk5JEKDz10GPnLaN+MCOs0_ySQYu2?PCM znOh1c6EH2|D1w+mV_av>m~8qMd?CZ|-!Fhrh2--pV8?OukKgRwT7_CRx0H4zRchqI z>!^?dL2nEE#k*0&--0Yi)KJ`?V73eVMZ**Li((U)4n-0ckQcxTg#8U|aRL;UG0KXU z0En@Q(5&dFzykPMq$pQmyh<^N30SzKC>93t7Qq)s2$6zjM*m#0bJS}K3PW)Pg7&nM z8jG}6)o}{LUu+Lh|DyklLJ#MB6P#^wQ)JC0yn!`cyD z<*2$Dc2Yq^7x62soKiFE44BDRt4g3Y5;{@9SG@K{m z%FSUP)=Iy-%PmNnThXsZ{R^HI9v97O6!Lgc;6=mVBZA&I9!o*=X_{RcvQ^#ewX?zw z7VsA@5cdh2XupX$n)mkkEn;#xA{RxplR9b5#IQ3Kkp_d}xy`QSne3E@4I+;UK0<7(SP?Ry9SwJAP_wA&4i5g4IvS9A*1~Q=cuE7K9;$zggVDT& zO>1;8j<|V&Spqg@i-6iLV-wjFkx5-kYd%$5UQVp7ZfR_!wFtFxcRa|H@aicfY~3pn zB35&%uDOQBp)`<@C{!=funo#qe1aO_)2m=AEfS?w7))EdF}2Lt*2b+uWE(}$;!Jsj z7AYRllCVx}Po>5(cn-mQc=hty{JDk6y$KJXt=BWZH$1+ST-nMlt|rf3n(Uv#elkFZ&!(<8j_V7TY!znAHSCa(IHPnJvXMwBPQVCCNiCY8k zt)kUn=YURrWi#RE7q@fyx;8l?(O=%+YbPUpPY;Qdb8)=j{n|a_~}Qv&-X)5Z}k59 z`Pj1ynTOlpVx{hH$6lWA`oog%yPf#!>w`aiI`Qk5vp@V{2Kb9xJ=+Vt*z(_>v%lHT z{O#JvzyD$Sm&={tUp<*IKAhCR|LXak`{`NV^A*n@4-!A^L{R+Vx6ik{k5(Puy{&wU zwC7^+i{q;`X90!hEnq~yUbp}4F!bwA=r13S-oHI_{gkO1wGLX#PLounDuuLy1v|w-k#Mx*l_*n zV(RIJ`%~-IMa;J&av8tlbCKGgPX=~sj52-@^cwd zEX&?MbL#iNU(A0S8q1s8>IltMWwjpyd|?~adwFi*`pSiy+e#x#bcjSb{$Pu!hN^T&4_C&wbWKSFTF7^bTr3}>&|E?Em0K|Rfv27Lw@J8 zeYgWbtPKJr2USBJ$40|k~-um#3URwgWPuJE4V z2y_GfqF0QbFjleuj3f9?z+V_~AgT`w#cUCLi#Yq=k44M{5ToWTUXBw%+ezRuP#cLn zSU3Ur77(0Ug+Y8lFZ|Xu8dWfgUxY7s25f!H$?TBBWNwpjOPuNko20@bELAeg(E3J< z2KEE!Y~U#s@wZS#g2f~u6vBqMHQ+hJ$PKns*n~hcg(E;2*lJ;yz{?^j#dXR|9j6V9 zlYn5LXAysal11io5r0wq0)KTKXHW}+`-BA)1_+{p1{UKSk5~j>fE^a@q*(s~6S0cp zU4USr$Q9S%1P~1V)m!EjDP=4uo>1_jrUw4Pc@qB5SUoOIk4J#c^H4EMpW#Hf@} z|H23w4~kB8-X}`fI>5{FN~(RLLKhvA;-J3OXKr_yXpw-}WuU~(v@qPN`A9bG=!t8x z38P&|m$p`k+D;mvL^hJrQIX5h;dXOfak<&t4%%Bp*brt^1nDISkhoabli&qb+8C$o z%+q0MBPeYFRZGgjhC2#EiraZLJZlH+)DoKm{7!rFa2f+gQ;)xYcPhI)APeY(PB|vO zAnpQ)IW`Hy$VUl$qNTJ|M#Bt_Zxw?M;qCN5D+HMm$}~{3LVXb={(v~$BBs^gW87Rx z7Bgz-%>tA96tRZLq_m5QU>y~4WG!FUW$g5o$WzpD4Nm;>7Lpjo7@|n>bLD= z3`=44C!g>7hWtv8e0Xgbs0sx4_Xe0UTGQLf)H`MG5_n{WQCNq77zvfkZ-L4f+%{1_ zJNM~9cxxoTH{ZQCS7<>e?Xs*VcW#c8vd|+sSTDAi`O&$a)th^JU!L3fa`)VW!-d<^ zw^yxq_k4G@Tv*>7hQ8hNKRgWmc%$pVZs5xe*XvLEKH2dGL>?@A{&uDR*>>XA zynA!f);*|=3}|F<3tQ;{R3RG_IfKU=j-M$1Js7_y>rY_}B-4w?bV5^e6``TD{LH&` z6~{6B1^yy@0p)N7^uKi{7{WHIU+;6UT`rD9Nz!__3OgIQ!*FL6%UjwT-tTDokWW5^ z?|kr_AwH5b&LG_eXj??y;y4m;j1yFOZXvuXEv zYtNACOW=1aZ?Dz0R~cy)j*e;$v(jQ>^$q$%QMF1*mZ3RJFN5`cJD#SVvZ?5E8^A$lM1PLs`y(VF%pK-C|!Y@U{8U-jLVUy;Bd3e9=66x3q~YfD+9gdxQd+6Qo?Go zS6&D}#5FYqkw}hA*4W+cpA_a{U^OyRUg+9qHx<#)W$T8SP@k{jwv;%Q%8;~2x(0- zj3rTtM`0?05i_?2oNW)UCTC*ch37qjp|Bk2i6(QwL`zy9hdUP9&Vrhdlo(TE16Yc> z7$r7bUcgRwYA6;hMIvYj8VEjhBRJczeeQ8fC(@>|oVhEi^r}e)P8s$Rc!4O2<91eW zTs_on0q@!^DEA6c*Vh*KUEB%>yV6WA!Pr;Zep*LA0|#t)eI$+TSsUzQ=^;mJG|ZOk znmA^vIIIdR<>&u!HG5$rFdBs!dty2b+^OT#gOHEVaCpobZE}@WikUCwZZK5jIbUI*&Nqjn8DJb&0WL7zu z)1tPk+xb-Jk3J|pRsrr+b0yeZ1k8R}M3%I@oOr53ir<#QUru2Xv1K4@nM8Viv?m0U zYS;?FliA|a!fin7)fj^2)L6D_t{?Wx{c8h413R3wNmcEcULTTGS1-)ywVrV`&6P}(APtHYECMu%eK$L~6k|?6#d!!_BGh`9ScZ0uy z+$Gi8WwwaP*Xw0jI3v5m(Gh>wL}Ynq@L)7Jm$eKh^?U1mBNMUYcy#I3Ce0(}*(9if zqs#qOYywCxatWQyZpK$1X3Ati6OKe~;|Ij!_5uIkrTId>fS$#Qz;jK`8uC+moyPV2 z;HSHW@i>f|;(6EFV)EO|!@qt$^YmK&%X5j>cc*^7w{-tvrck#Y_?{kko*e~W-s*gO zEBEMZ5Tc|%-Ok_N@jgBmdwn(g@@m(22hnfVeXlR&Kz07ahQC4 zqwfbm@a3-87t*ixW8WixaK;Ghj3=9(UyhQG)?F}@gvB)KT=-o5?Na8=p7;5t*>w=l9YG`}^K9ZdL>PJhC! zO{zgThG{dX!V|0gx}c1wBSUA`zdzs^@u)*GXQv@G;_~JcE0=nv4r0C@{myjo=e@3f zIgI{zDe&c`$oiCfAYx_eDD})LSKJ=Yc(qEp+tB*$$H>06-I>t;?PBgI$5zs$-`s-^YHS znNrh6huo>2!LO=rJuc8wHEw~yD~_a$^o~jf;RAZ(G2ky6o&~`Xs|+k1C2mZFUV2=;Cxe5urR>`b^JPJfI(6Q9g zmYX-$Z{1warHm}{akHoq&)lS=dol2}!nuy-9&jN)8k1ACm<0SqzO50?y$G_AH|Zty zW(CouZ$qd(YD^4LfxI{Zg0WD9;@v3jNl^cyBMr`ySJQ@7q&*k$7Z7X&pz~_sQYfcY zNNE*(N-2waM#8U$6|+H4811VFl5F7x*^47h+hHmIZne3f2Fb-r}T?hQKX>t_R=?0L9G<_aFsJ zs=A23;1~mff5TrmEf=fQB6b?J{!i}+ip7Dbg{RsDv)fL(wuFc-&^ft1uYC3M7$ zsU@Rr0rDo4M4SM5-JCK&Fz^?s>J`)_b=0V~?O-a}52G?Cx7#nms|zdYQT(P9MBuNJ zU5=~aIw7Dxx4f_cfSHM!+?mv*Q#zZIkN!4zSx5(t8kqq@N6IUP)r=Nf4jl#uHw`v`2Rx_itqu;*(%n4E%)yHter~yuja>j$)TpqQ+E-pZe$8(9B6_KoDrAuFLBRl@e?d}t+6 zMKrd8rFZM;B6`DEn@h$brD8cL%JjSiC1Duy2&{9SjB*7_&AM92@+a4bP1N7)hU z4TA~E;I~LLY!tBg3O&4eU{APqZX9ggIPmlZk&&&oizO-sn@ey9)S;Bw;*-0hj{d>O z(s*dLOFNm8%@5d?=To7Wc7HX$v)a8hAJ25EqggEisbTF4v8}n!8<ijC)ElEbkAWxCAA@B?KS%|u0M|Gp0?uzmr z>rBQxRBM?+7=}9O+4=Y{H+uefGyls+c^GayJ(~myKiZA{c)9z>i@BdKcLRd|^y%my zZwHLD{rmEzqtu+^-M9Apd+jXM_dEk9(ma&+5lr|LZLejxW}oFE?B` zdA4eQvTS`aTL?=6d_P=ue828^x?+JN*0VV+IMQfS!$R%z8L@O!{x8; z@6TNrO>OsQ&&{NEXJT8^Jva7j+mmBgmc}kEMCQ8WVZA0|f+s2%^=gMAH5FajAD74| z9A4Afx!KfML}Z{rZ8v<-FY^hMUV%4b7+p#Z&iQAzqB~c*d&WG|{g!VxQ!oj6e$MmR zt|uGfxy_>ZpjT*QVd`ObDBM=w;(+b>rxOpZq+!4LdOwEI_D{RTKj&HGLDCza~Lza^1$s+CfXGzXlc1a4_9rL~t(In@Gno6W{E@ar35qNKJ1`Y@;mBVTg%C`I`~{k^?ay}@Zkb0800H}Zyjh^#1a&|wbWAtRJ9?w zHKA45cuY}KHSq%;xfCTZNP^0a>Ou>Yb{h3Bh$Wc$qQ45*#VR(Ri~VOnn2}u#rWRZz zEh>r)ZDboqYGOLN?Q9!IozNM(tg56ACx{9P4+VPn#_;!r_)(RyY~Q^wax`b?akZLQ zNd86g0=$6uPN5>85Zd|BFGyS>hJ@BGqEPr`L?5>Co8fm&VAhm3pDKVat%d;C>$V!W z4Zw&1_*+PKDn9}IrIKq~n@V}iIzC`m(gX|Wm_rnEiU)FzmD#jfNKkMKMW_*ObL={U zfeF~6sS$Y22iBXWX3|@7z@@J==7raMUNL3V%S;)Vq92kJ_BKk z{bw|#fx=h?&XtUSDi|GUEP#Fyg4OgY1*=xdt5Yb+b~g{nbY?wO3O6eFNy4=QOQev1(#z{ z!8;320BvMUHa#Yq$4HGiJK_!|a&K+ID%8IKK1hTLDqUqW@D~_bXg>355jp^fEG|G* z@dTADqKHuW0x^M}xGe}yC|!$43JWPf4;Jb^08p_8G_xy!O_2GZ;amhM95MgJk44}v z7SXsLbd`(t8et`5$n{u2-mIk+5DfgyS=&(jq67v6=L~ItT_>vq_#2Vdqs+(Cp3RyD zLb8=1PtGgAMg_eBG^>+3QdB_*iECj>X>31fVw48ecvXO-h;9dFf?&x38YGt zV~T_U>ETcXq9R7js5jxjgtwMa&wV=!h5#1$3n7v%>+$460*9=gO+vR>Y*k3@Dw#vw z%%Z65da$h&R&4`~R84NEZ6grqEj+!jgj7yqH(Nrs(Zx}PS&7_v;4j?ZA!0&~1Jrz| zf2C$24ID6eJ1SpT%qh&`zR9kc%}Gbp3f&(j&S=)D%_6f`Bh>LWF0FgBf$^>BgHMl~ z8K=S~38!5ahg6|#Pp7Pt)0uEgJ2ntFyVkuq=9$l`Fbmk8jqh&{`2w1lOElbRp2$10 z8Lcm)61&+fCx`CjBX}`9ksvE6m5i!7xCKjFp+drT%G2%GyS;Vy$ImBs2QGZFdhYVn z=6Y9GTC>rwTkAJ0bZa-K0_S)73|9L2TWdpWU9jB%dkq4v@w3I@JF;CTfXCN-KD zf~H`P7bGr3r5m~&^}2T8uOVqgWH3S6h6M0|{i&|4Q7kwt^-aOt$#-Kv@$!1lv;Dy1 zEj#A0kM~>;cf+8?zBr1#z7l_Qw$OZjaz6Rpe(d$x@RM!N_Z!Y9K*s&x4;Ry~&L@7p zlKuI5{-b_xi`bI@j~jmV0H$u{vyB8=m`g zC$!q@U(ciV7w7ODA=f2rNT56XWHa1plgX(X9UFFq`PmF|UFQ~(^M^yuqzbG;Q0e+c z-E+&~sagAX->+`(bfbHGv>ds!;eCESh?#iIMb}#R_K*S)3E*Q=%ORgXnhV}LNTEyc z^YtzyPymAei*+V?uWzFbHSawqS&2F4 zoIw%<0fIy#h)jUUIVTbT1DJEpIcEh@(XwUPmaLqkC1<}hVdrY*w(e@~_UdYH>uzRt zd=24^=hbZ0zrOlNQxpw~?63RRziwsMawiq_iAhJxGea=g4dO2*h8O_{{Z~MlKL=mj zqo5q(Gc7lSj@V~%a%Dv-fs~L{5}ilOh|CYmtj;0BrKX~CT|#A(V)?@S=$YyMozXN# zP9Coq9a#Eqt8bezc=9!s7EHGl)r* zqB1<*1jOh3IAj4uq=rW%g@(l(M;AHxZ&divw3MiVyyTqRSUl>aWgTbKdqBA^4tA%H3FAt}R&gZJ>tlG&u>s*-q!>MU?_;cwPi6u{Ke``kO1Nu z&|u%TAq4R^c>M)`gMSbx23M7hp9N!8z~0PG4$98pyue?)2`t9Fm7QT`rP(=I4sNyv zl=E$|0xV&8HSloKT`%l(@#WQ-t+pCy1uS9|)NCvADzW7IHfIuFIsWgkRb)dOQ7r*( zt2!C6y;tvVQ&v|cvnheaXSb->rKxmSxQ#xU%g$8_5eSy7*A;4HSvqkhND*@=RI1YIt+p z-P@2`RmhaF3+W|Htkb#mOc7h6lhOE0W4)zX%qgXj(7TsG$gWZGVz8rBnpq{JYg~GS zZ@e4wUR-7(b`{Z02JnTOqKsLDeiKAam9dLz@UONok;bR+lr{Jn1o*=1g`}+H?5L_5 zqQ#@txz*6L`{oC?uIz1oyx%t5qOwZ;J@qz+6uoi|tEjD6?Y8k3N33J*@=h14ze(UW zRd#jiTG2_T=d`uyn>^xXx1gz6(lTUrk6L+7Asi!ptNrNH3CRn8KlQ_4%W6ptfv09c zu9vzvYv;$d4~B2w*}8Fces|6@)*>1AR1P@E^X-D^w%V}{>EcX%Z@&p!#{T(k$FT3$ zsmDNUv15o3MU~%Jz%O%j**IEu8LyP3W)cK}{p(UaD^EjXm<5`4i@+%@ud8gH?Nqm! zQAJuHrgZkp`?`fY6Us{ylF!HZ-|v|p&)3};<-jg=V^;a)qWb2#_Vz|VXMVENaC^b_ zWLa}>Mgax*E*x3Yif8MV`%8wW8#drC^ye=ZjF<)ATd}=4-TZXZjdAe3HT!eu&l|2g zi$?4mp*Qf!vI(RWmgcWEZSenq_M&G2g$tkea*@UHY|#Lm#d!o?IUz?t2VBq?@7@@e zVuKji4ZqN{6$5nX+hc-9(~^hd0sR?Wg!ugEH+*)c`O%*D!A`^J?T*RKcFma0dpOnk z$wvL&ly<(`v^g^N$x4}%U)8Q9cqQ1wPZX6UG7F?$?b_i~J~5%bUR6<5a6I9CB&#f} z_sq{U4$XQ-W<1N=y&5A8*fh{B?Qi4WyEb&`R9{bz5>)ZRiuKiLH>TUIPC8djuViL& z_yqW$^Hbin2=hOlcY>0CcgFklR0E!89xhwH+4ntNwY@&ogxB-#rVFpY>n;1=Ug`e& zRMU(7=F1bhE3?+Kqgv0H8y09ypQW}#%W9CQ`m97nCDLrH-dbX1Vj)&Y=o!-5GBPnf zBJ3|J%2Nvnv4zEP8QGzL;P|8u2&D;>%FLwHqnX(e1WE?DC!Lx!U}fE1blyX%=coVy z-2mTDC#8?))epy{UyjzTwK6YnxfC{z(1DU*auhkOkX?+Q6y(E16^7;{hf;}Yxj7M` z;r}T<@knWD8X-R=^w@9Ep_yHjj2b3z-iWuQNU0f-Om>;hDCUZ)ddJ&bT{fbyjN_^` zO?U@BnlH-;&xw7nH1!1XB&m7fRr#SnURpsYP#8Bs&KpEwfX-V}Ry0^7xFk6{q@pkq zJEx`Pi7B}!(S@X}mz0W$2+w8OxPzxgXp@D_ti_qKOKsq1Q?jlelJXdSyCAL_z-%`WJY5P7$l1j9)?)m8FuB!ZIVke?!tj zPs9hjXDA{E_~K+`BqSz;rDeqA7bO*uQpnXgRR|@kh({?QF$aMXaeVXw69TSd2<&h` ziHHI4;@1-SnyLzJK{>i;E3*VeakZ83Fed>h|0KBwqZ(1__crGl?*!W71btQz2k=th zKLL4xxw!rU#KDOz#OQ5Z!ljB;t1m-faw8l-A|3I6XCtUQ1()^!86TSginE{=!V96-h=t;xmH;B1FVch(3fV?b*0Or&TdcbaI4a9Wp7S4_zZNg ze(1wSghJyZsqv@)#_}@4tF`?6HlGx+7(TzEbI`oB(q`Aw!1raPu^tJrNzd?Dc*xo4 z>NfcrYBgd4ENXTe$*Lz9r8zoo0DKh{k(gNro*6g+y;_Q%sj>)!e!zgOK{PAcuNdi2 z{&9kWJdoERF2N30K&hsu=tKk|2O?Nv0fO%;^DyK^C>%-0!srvaP&zvw1uIM|U)yOm zcGwYL4A{lNb}&*n%4?}`VO7-8cqS3rvGeH!b-j+QA~bai`6Yseh6fGOo5=lMi@IQr<*i?X0OWB&+L7vd6>v@B8zMNr0&R+h6$ zz!?Qacb98!e{p(me)i0=%BB))gn0Df)>hPt zE1JFX^@aBF9@DAyX1|x?Zx+G-?CH_^r@X2*9nzCpVGddExpHZ4eY4xysdNsQA!*KS zjWi6_y9V5#Gl&?%>u@wX1XV{!gKr+zQ@LpaBgT!DrrCbYDo(e2vVpzSO7GF<_M1y4 ze5__e`NF8pW@aob`5Px&m0rzX9QzA>r%l^!H;#Cv9p<7sYCba$613PV@(eXdyb5WX z9*sGfN~(LYWAvlt&D&><15P~o;H=&}J#=nva8x@vrrtnl@4OaK&$oc8Gx8^EMu^Eb z=JlV=t3F#&-`O-lWDY>;n)~jI^xmxOGjs()nx2+D->^PeH9cK3zd{7ZP6K!@Y6npP z4CNUT^mm7Ck2l>I2Sba7{)}v^SKH2SPI>Oks&7q5AI@vOTCeH%v=C+yU3n#rf7V+w9!l>)YJx_aKv7Pj0PeEcS^%-E!YN=-b(9 zKDf|#?V#n=*@ib~y|cY_GAoP5%&K8$mllQQ#Q(*Bopx`-`*PFu?WP?s;N4Xde`~I(0<iDtT1HRx zi`*PTyF%ZBitWUtf{>)_V<}n36VpG8OFvRmO9CB6JVi$KiOignIGD7esvtb-KP4x9 z7>Fyc$w!md;i&2UtN|TTk7h)0xIM;0&XWH1n(6tR=E{(Gz(<`~GO_h^L4&x;APcBGS*55fE{=(a`pd+)qsj3hQ77I%67nlB-|(0t0N=nh`h#O9 z|1u{27^$L&R9S5I7}Yiz7T%FP)p2@E&}AskibVbff@Xog@M6#l0lQIH8Vy1)faVtn z4o*B_*2M<^f3cc@rb0?t0{%D4sHwFmFya<vp?aUe{$LO3NclV+weM`c}inC!4J^ zZKFG5-Ag?~o5R*_8+r`$#6;{>y_0b?qBJ(ECZ8xJ=kbctX_=ZPJ}6y>0(^nRzu+%!f(Kj-6d3pmTm~rrJN^>U*AP!DjV2dI zQc5G~nEaL_ED`)SfVM&W{pB7UHh2#>MlT-jk-*F<2w~=*#B&k8BN#WkwN)5HgN);E z!M6sJU&x*)u0=*=0DrkT1{o3m#&CrSjm}mz4`mHt*)c&9r(>nVJRAr>#(HdN6q*y| z6AFi7m74s7Z420w2_%=!3da>g}q(4p0HR1M8o|=mu_jqVS6h( zd$pC#Mg~Z(nw6=e#p6JuhHV@EC@e$ad*L?F)Rr2FrmEhrYG|w*=`*3;2o5d}Gkbc# z+R-Eje0V%Ei-}`WSK{T8&=T~re1kO4Ajp7RfJX%g=D=Lk%<5}WA>gCIFz_ZUUey`! zyg`J=-;NhwQ=NrTG9*tdP-B%C-&V9xsd#x7U6n#ftzhKjmm&T=CMxOpad`0D5|&MX za_TY}m1*J{du;A8A2Nt2N*2c?0t<%Exmr~N5mn*SwIRHBy3;%6=bI#i8WNF10lZRc z8GMzP!l6NVM%spduv2DMtL%En(fELTTCva|rHQNasihxApL{PI5kRrn_B|2zK~!1@ zG-snvZSfnVb`e=ndLsU4cuI)EDpk8xgNp;+0bk3gA0e3)tYSKsG&H@w0CPz+uF80=vnFJHfdUx zTDvDbvonoTGhT$qNxiik6|HZ;vv4>+b#5N!8D>MBw8w&!p1AU4bS1a<$b`bQ_J-=2 zc5$zfG;XC#J1b^f)M0(reh+uHzGB2)(V`>uG>JRflxT0Sb4uQc{7Vd~AQJYSn&`i{ zV4rJ+`4egLaAhNG7E6w%UVEvUjung?4Glp+!9>1^k5(W-pd)7g&SA?!XGfQId#ht% z+_W*F+Ze3-WYux+wExP2_4I`H;*8R;?N;pYCT6F1+T@A~RY6aL`+IV}=7 z9?mLnPf4y%2=6Z|Z_lW{7_0mJ<&J;2Iq`7A@#T^k{1>Sp+tc=suFkAqTO7Hv*auni zlMM{M`NQt6?SbJ7a~!`aR!~^suBE%hC2|@z!iwlw_3fsj@=RE95bOzkvZ5xht4+7D z-a0sB>>D)o^lBRHv>q?>+E&A(GflTow|suF_xfjJ*UvTGTGc$*&>zeiy1L{XULJ#y zTA1@bqx9IBN!^Q6jo zB5`$6+tJM6=<+J0#S{&N?G#k1=;+ub({uC4iK*ncG6GCTM~m~rN(&+rV}6qycQh{Y zSm@FBV7o#KFuH)DJOg%P6OM<3{5mY`9kyCr#;)Ya`Gw@Xh}2LdU2q*jwnNA)PG*&0 znK!kDi2cyGV2dAM7ki^XVFXIxK6vnJ9~78Lj3wusAY~l`StjR)6APo*?0i^=t7H_a zxXe4~M1LRZkfKXtI8FiICsj1aTc`XeS?F8t9oZb7Ju`zR-l+V@li4RD3DMUNroKF=lcuu4H90+ zcmeQ53({L&EX3X}mUhd~uoDmIUPMj;lmo=^n;BX$ns<==k95bn$^;ykd|*pfB0sr0 z9Up)L*aiLu;TZT^m3@?)^8u$kN(v5Goz5nN)S_A!t@K#fp(X*%G2aCKBJ=~xHD+bG zQCY65D^UpxuA{Mu6JWAIlQZP*;z%4UJ}ZI070JIS&%d~^0Kxd+KPSI{ z&Y*`Gjx1P@aQOKloSfslyp!VMNLg8|lo;T==okY2N=qYy;EOBX^9%p|bNmeuYFcbi ze+C2x&Cj5~z+W^en5)yRP|K?lfxK`X1A-f+C7``cCZKk+uo#7x0_#qAOu{!;#e#1fdDjVQM0v0?jJzBSd0}7+ezSnT7GV*9 z7~croBTbrvZxcIHBqi3!%M0o0*%fI>UyRBQL#em1*Uq-^Ypep6p$4{FwO@yn1N&sF zy2EDbbYzrgW|Ol>ymFK>U^Q6NZnY2jT*FOFy)cJS9ABC-cepOGs}c$`;J=E?PgA-; zdW|L36)<1HidP zXNT^6u`)fRTc0$XpErHJq`SGGx;-bmF;jPaT5@w%a(7XF^X;3r=T%?ME1zszAFi8G zdjty>e9q5zy`Xhp&gg>R`*7KMf6@HY`Hsg(ie9zdUC;r?Az7p67sw0z#gG^0b|8gP z^kiE3V7KYswh!G6PfoW!J=2Cazxin3k2j`Yo^HgT8RKL8sT;$>FULgy-xsHB4>oOg zR*YZmxPChD!{2p#(fsOS$4@uLCOgDi+y14)k^b$zj@7=l^`VY)^Sbr!zRmuIaSwh8 z*LtLg8;UB8&tm4H>ZqJw0<9Gp&Z!mI*?c11P}A6F9~yQA@}+0o!{gSG3ES|1dTmVm z`MMj+R`<>{+&$m^_}bvTbB#CGu)3@La@%>Z2D+JC&uHnQ;L@x_Q!h-SJvz|E_5Ai`ajy{krSxbFJ5AH7Lb^?mgBcb$8dA z{Q|j{m%~nrEeOpc#Ie|g7`B#ha!}Kgk@7yd5G{d;x$z&Q#U6$D91(g9)85#mlOd7s zg-5-AJmgmq5%1w7CZ3dccyrj)oQfhek*SR0wY^yqt1uL?@R?w;@reCW?7(?UN?IEq5;V^K$-KWF45re`N4X2xd~rDF*z zza#}dbL=CNprdN2bxl$NC)eNsc4<00l?$dXZ!Ua4W)`klo>B2B}j)Kws_9zPv2x6}$3kfoL?XCk$@LO{`Y zv=XOW+h%o7w6ZLUA#50PW*yh#LG8Hwp4x7;{ADi@b`4y*^+on40 z;{%@Q#evyV^P69s!SDID<({##Q?P;@9Lx;)bwm9Yx{gwAWtFRGd|eIx_ghzc3$ZV) zsgjI080K3YbFJaT_y%?1l@<4bhc#^|-LO;kJhW5Ij2UC$s-3W8EuJwG_j=`n4Sb`L zj4dRtqEe`0#U&ic$%)D+PWZ4OA`O}Od_od42eol(p9-XyETM26weGpLmQ!Qoda=LT zzO+9%cQB*&Ytd4QC;)hUXUF~R{r;v7*M(2EPMw===`t*D^)GGoKmF?3`O6cR4+pO8 zG+$pf0c~&3iSIAVA8u&_yGTn41Z8|NTX$e6i}jx#=>G7=c!Mx(hmf_`r^UjU~t;F{iblC3s z@l+G`o~|vKZl7t~ow1!e+q->kY~k$0-sd|*`xE}t?P(NAF=!d&>9p zg74mG@Asb%fB$*+>x-^8mt7C`ocK~PZbOH1S?PyOjK$Ld}!>LIqj z01-ZHzQ2xF%>HDj{?ke2%L&cv72B&l-<5e#V9mjb>(qk1r-6>uzfNymXM?20&WGca zTa_Ublva|HsTHuZ(!0l7Fk+wzDHV*O)c6xlwNNIfXwd=0EvS>0NPl01t-8SW)?+bod>6;FdDJXC|>|itjIZ0nHK{5WfQTOld0qut9T{U@^rb9Y4@o~ zyy9AixN)jQV3*`p7vTXOre#bJhS!GWE-6J+UTYCX=7ynRFtseT)+$CI2HPxjk2PCH zd^Pxh7PWe=&9T~7YUIRJW#w{8(kip#2?@oV@<1ePMiinsj>R5@hch)N9-E9uVkp6t0ET zbU{TLuINJ)RU*hDg+oe$^9rFQ0qb&UJhwC!19VuO;j_XOQ(ZW$V6Vd57St670E)sv zXwDd1;)>tuU|u+==>Y^+7COjZQ9ll1-GRVEu( z@y>{cHH*PzM5INf5i|3dCE0WWμ$hq1-Tk}>FFinrH^7@Xd@&f8z#oIjZ38aRmH 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

bb< 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%0D& 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

BLN!Kk^`qxSvj-Ks(mgjYT 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

#^Y!!U@@Zz`FgLfK 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

AQIg$Sa4(XI#kdJ{#@Swk4yIV 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 z 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%0A;Ob)bfEhFPsR~o8T{Msv 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 diff --git a/vnc/vnc.c b/vnc/vnc.c index fd5ba25f..3d155a21 100644 --- a/vnc/vnc.c +++ b/vnc/vnc.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - libvnc - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * libvnc + */ #include "vnc.h" #include "log.h" @@ -26,814 +24,909 @@ /******************************************************************************/ /* taken from vncauth.c */ void DEFAULT_CC -rfbEncryptBytes(char* bytes, char* passwd) +rfbEncryptBytes(char *bytes, char *passwd) { - char key[12]; + char key[12]; - /* key is simply password padded with nulls */ - g_memset(key, 0, sizeof(key)); - g_strncpy(key, passwd, 8); - rfbDesKey((unsigned char*)key, EN0); /* 0, encrypt */ - rfbDes((unsigned char*)bytes, (unsigned char*)bytes); - rfbDes((unsigned char*)(bytes + 8), (unsigned char*)(bytes + 8)); + /* key is simply password padded with nulls */ + g_memset(key, 0, sizeof(key)); + g_strncpy(key, passwd, 8); + rfbDesKey((unsigned char *)key, EN0); /* 0, encrypt */ + rfbDes((unsigned char *)bytes, (unsigned char *)bytes); + rfbDes((unsigned char *)(bytes + 8), (unsigned char *)(bytes + 8)); } /******************************************************************************/ /* returns error */ int DEFAULT_CC -lib_recv(struct vnc* v, char* data, int len) +lib_recv(struct vnc *v, char *data, int len) { - int rcvd; + int rcvd; - if (v->sck_closed) - { - return 1; - } - while (len > 0) - { - rcvd = g_tcp_recv(v->sck, data, len, 0); - if (rcvd == -1) + if (v->sck_closed) { - if (g_tcp_last_error_would_block(v->sck)) - { - if (v->server_is_term(v)) - { - return 1; - } - g_tcp_can_recv(v->sck, 10); - } - else - { - log_message(LOG_LEVEL_DEBUG, "VNC lib_recv return 1"); return 1; - } } - else if (rcvd == 0) + + while (len > 0) { - v->sck_closed = 1; - return 1; + rcvd = g_tcp_recv(v->sck, data, len, 0); + + if (rcvd == -1) + { + if (g_tcp_last_error_would_block(v->sck)) + { + if (v->server_is_term(v)) + { + return 1; + } + + g_tcp_can_recv(v->sck, 10); + } + else + { + log_message(LOG_LEVEL_DEBUG, "VNC lib_recv return 1"); + return 1; + } + } + else if (rcvd == 0) + { + v->sck_closed = 1; + return 1; + } + else + { + data += rcvd; + len -= rcvd; + } } - else - { - data += rcvd; - len -= rcvd; - } - } - return 0; + + return 0; } /*****************************************************************************/ /* returns error */ int DEFAULT_CC -lib_send(struct vnc* v, char* data, int len) +lib_send(struct vnc *v, char *data, int len) { - int sent; + int sent; - if (v->sck_closed) - { - return 1; - } - while (len > 0) - { - sent = g_tcp_send(v->sck, data, len, 0); - if (sent == -1) + if (v->sck_closed) { - if (g_tcp_last_error_would_block(v->sck)) - { - if (v->server_is_term(v)) - { - return 1; - } - g_tcp_can_send(v->sck, 10); - } - else - { return 1; - } } - else if (sent == 0) + + while (len > 0) { - v->sck_closed = 1; - return 1; + sent = g_tcp_send(v->sck, data, len, 0); + + if (sent == -1) + { + if (g_tcp_last_error_would_block(v->sck)) + { + if (v->server_is_term(v)) + { + return 1; + } + + g_tcp_can_send(v->sck, 10); + } + else + { + return 1; + } + } + else if (sent == 0) + { + v->sck_closed = 1; + return 1; + } + else + { + data += sent; + len -= sent; + } } - else - { - data += sent; - len -= sent; - } - } - return 0; + + return 0; } /******************************************************************************/ static int DEFAULT_CC -lib_process_channel_data(struct vnc* v, int chanid, int flags, int size, - struct stream* s, int total_size) +lib_process_channel_data(struct vnc *v, int chanid, int flags, int size, + struct stream *s, int total_size) { - int type; - int status; - int length; - int index; - int format; - struct stream* out_s; + int type; + int status; + int length; + int index; + int format; + struct stream *out_s; - if (chanid == v->clip_chanid) - { - in_uint16_le(s, type); - in_uint16_le(s, status); - in_uint32_le(s, length); - //g_writeln("clip data type %d status %d length %d", type, status, length); - //g_hexdump(s->p, s->end - s->p); - switch (type) + if (chanid == v->clip_chanid) { - case 2: /* CLIPRDR_FORMAT_ANNOUNCE */ - make_stream(out_s); - init_stream(out_s, 8192); - out_uint16_le(out_s, 3); - out_uint16_le(out_s, 1); - out_uint32_le(out_s, 0); - out_uint8s(out_s, 4); /* pad */ - s_mark_end(out_s); - length = (int)(out_s->end - out_s->data); - v->server_send_to_channel(v, v->clip_chanid, out_s->data, length, length, 3); - free_stream(out_s); - break; - case 3: /* CLIPRDR_FORMAT_ACK */ - break; - case 4: /* CLIPRDR_DATA_REQUEST */ - format = 0; - if (length >= 4) + in_uint16_le(s, type); + in_uint16_le(s, status); + in_uint32_le(s, length); + + //g_writeln("clip data type %d status %d length %d", type, status, length); + //g_hexdump(s->p, s->end - s->p); + switch (type) { - in_uint32_le(s, format); + case 2: /* CLIPRDR_FORMAT_ANNOUNCE */ + make_stream(out_s); + init_stream(out_s, 8192); + out_uint16_le(out_s, 3); + out_uint16_le(out_s, 1); + out_uint32_le(out_s, 0); + out_uint8s(out_s, 4); /* pad */ + s_mark_end(out_s); + length = (int)(out_s->end - out_s->data); + v->server_send_to_channel(v, v->clip_chanid, out_s->data, length, length, 3); + free_stream(out_s); + break; + case 3: /* CLIPRDR_FORMAT_ACK */ + break; + case 4: /* CLIPRDR_DATA_REQUEST */ + format = 0; + + if (length >= 4) + { + in_uint32_le(s, format); + } + + /* only support CF_TEXT and CF_UNICODETEXT */ + if ((format != 1) && (format != 13)) + { + break; + } + + make_stream(out_s); + init_stream(out_s, 8192); + out_uint16_le(out_s, 5); + out_uint16_le(out_s, 1); + + if (format == 13) /* CF_UNICODETEXT */ + { + out_uint32_le(out_s, v->clip_data_size * 2 + 2); + + for (index = 0; index < v->clip_data_size; index++) + { + out_uint8(out_s, v->clip_data[index]); + out_uint8(out_s, 0); + } + + out_uint8s(out_s, 2); + } + else if (format == 1) /* CF_TEXT */ + { + out_uint32_le(out_s, v->clip_data_size + 1); + + for (index = 0; index < v->clip_data_size; index++) + { + out_uint8(out_s, v->clip_data[index]); + } + + out_uint8s(out_s, 1); + } + + out_uint8s(out_s, 4); /* pad */ + s_mark_end(out_s); + length = (int)(out_s->end - out_s->data); + v->server_send_to_channel(v, v->clip_chanid, out_s->data, length, + length, 3); + free_stream(out_s); + break; + default: + { + log_message(LOG_LEVEL_DEBUG, "VNC clip information unhandled"); + break; + } } - /* only support CF_TEXT and CF_UNICODETEXT */ - if ((format != 1) && (format != 13)) - { - break; - } - make_stream(out_s); - init_stream(out_s, 8192); - out_uint16_le(out_s, 5); - out_uint16_le(out_s, 1); - if (format == 13) /* CF_UNICODETEXT */ - { - out_uint32_le(out_s, v->clip_data_size * 2 + 2); - for (index = 0; index < v->clip_data_size; index++) - { - out_uint8(out_s, v->clip_data[index]); - out_uint8(out_s, 0); - } - out_uint8s(out_s, 2); - } - else if (format == 1) /* CF_TEXT */ - { - out_uint32_le(out_s, v->clip_data_size + 1); - for (index = 0; index < v->clip_data_size; index++) - { - out_uint8(out_s, v->clip_data[index]); - } - out_uint8s(out_s, 1); - } - out_uint8s(out_s, 4); /* pad */ - s_mark_end(out_s); - length = (int)(out_s->end - out_s->data); - v->server_send_to_channel(v, v->clip_chanid, out_s->data, length, - length, 3); - free_stream(out_s); - break; - default:{ - log_message(LOG_LEVEL_DEBUG, "VNC clip information unhandled"); - break; - } } - } - else - { - log_message(LOG_LEVEL_DEBUG, "lib_process_channel_data: unknown chanid:", - "%d :(v->clip_chanid) %d",chanid,v->clip_chanid); - } - return 0; + else + { + log_message(LOG_LEVEL_DEBUG, "lib_process_channel_data: unknown chanid:", + "%d :(v->clip_chanid) %d", chanid, v->clip_chanid); + } + + return 0; } /******************************************************************************/ int DEFAULT_CC -lib_mod_event(struct vnc* v, int msg, long param1, long param2, +lib_mod_event(struct vnc *v, int msg, long param1, long param2, long param3, long param4) { - struct stream* s; - int key; - int error; - int x; - int y; - int cx; - int cy; - int size; - int total_size; - int chanid; - int flags; - char* data; - char text[256]; + struct stream *s; + int key; + int error; + int x; + int y; + int cx; + int cy; + int size; + int total_size; + int chanid; + int flags; + char *data; + char text[256]; - error = 0; - make_stream(s); - if (msg == 0x5555) /* channel data */ - { - chanid = LOWORD(param1); - flags = HIWORD(param1); - size = (int)param2; - data = (char*)param3; - total_size = (int)param4; - if ((size >= 0) && (size <= (32 * 1024)) && (data != 0)) + error = 0; + make_stream(s); + + if (msg == 0x5555) /* channel data */ { - init_stream(s, size); - out_uint8a(s, data, size); - s_mark_end(s); - s->p = s->data; - error = lib_process_channel_data(v, chanid, flags, size, s, total_size); - } - else - { - error = 1; - } - } - else if ((msg >= 15) && (msg <= 16)) /* key events */ - { - key = param2; - if (key > 0) - { - if (key == 65027) /* altgr */ - { - if (v->shift_state) + chanid = LOWORD(param1); + flags = HIWORD(param1); + size = (int)param2; + data = (char *)param3; + total_size = (int)param4; + + if ((size >= 0) && (size <= (32 * 1024)) && (data != 0)) { - /* fix for mstsc sending left control down with altgr */ - init_stream(s, 8192); - out_uint8(s, 4); - out_uint8(s, 0); /* down flag */ - out_uint8s(s, 2); - out_uint32_be(s, 65507); /* left control */ - lib_send(v, s->data, 8); + init_stream(s, size); + out_uint8a(s, data, size); + s_mark_end(s); + s->p = s->data; + error = lib_process_channel_data(v, chanid, flags, size, s, total_size); + } + else + { + error = 1; } - } - init_stream(s, 8192); - out_uint8(s, 4); - out_uint8(s, msg == 15); /* down flag */ - out_uint8s(s, 2); - out_uint32_be(s, key); - error = lib_send(v, s->data, 8); - if (key == 65507) /* left control */ - { - v->shift_state = msg == 15; - } } - } - else if (msg >= 100 && msg <= 110) /* mouse events */ - { - switch (msg) + else if ((msg >= 15) && (msg <= 16)) /* key events */ { - case 100: break; /* WM_MOUSEMOVE */ - case 101: v->mod_mouse_state &= ~1; break; /* WM_LBUTTONUP */ - case 102: v->mod_mouse_state |= 1; break; /* WM_LBUTTONDOWN */ - case 103: v->mod_mouse_state &= ~4; break; /* WM_RBUTTONUP */ - case 104: v->mod_mouse_state |= 4; break; /* WM_RBUTTONDOWN */ - case 105: v->mod_mouse_state &= ~2; break; - case 106: v->mod_mouse_state |= 2; break; - case 107: v->mod_mouse_state &= ~8; break; - case 108: v->mod_mouse_state |= 8; break; - case 109: v->mod_mouse_state &= ~16; break; - case 110: v->mod_mouse_state |= 16; break; + key = param2; + + if (key > 0) + { + if (key == 65027) /* altgr */ + { + if (v->shift_state) + { + /* fix for mstsc sending left control down with altgr */ + init_stream(s, 8192); + out_uint8(s, 4); + out_uint8(s, 0); /* down flag */ + out_uint8s(s, 2); + out_uint32_be(s, 65507); /* left control */ + lib_send(v, s->data, 8); + } + } + + init_stream(s, 8192); + out_uint8(s, 4); + out_uint8(s, msg == 15); /* down flag */ + out_uint8s(s, 2); + out_uint32_be(s, key); + error = lib_send(v, s->data, 8); + + if (key == 65507) /* left control */ + { + v->shift_state = msg == 15; + } + } } - init_stream(s, 8192); - out_uint8(s, 5); - out_uint8(s, v->mod_mouse_state); - out_uint16_be(s, param1); - out_uint16_be(s, param2); - error = lib_send(v, s->data, 6); - } - else if (msg == 200) /* invalidate */ - { - /* FrambufferUpdateRequest */ - init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 0); - x = (param1 >> 16) & 0xffff; - out_uint16_be(s, x); - y = param1 & 0xffff; - out_uint16_be(s, y); - cx = (param2 >> 16) & 0xffff; - out_uint16_be(s, cx); - cy = param2 & 0xffff; - out_uint16_be(s, cy); - error = lib_send(v, s->data, 10); - } - free_stream(s); - return error; + else if (msg >= 100 && msg <= 110) /* mouse events */ + { + switch (msg) + { + case 100: + break; /* WM_MOUSEMOVE */ + case 101: + v->mod_mouse_state &= ~1; + break; /* WM_LBUTTONUP */ + case 102: + v->mod_mouse_state |= 1; + break; /* WM_LBUTTONDOWN */ + case 103: + v->mod_mouse_state &= ~4; + break; /* WM_RBUTTONUP */ + case 104: + v->mod_mouse_state |= 4; + break; /* WM_RBUTTONDOWN */ + case 105: + v->mod_mouse_state &= ~2; + break; + case 106: + v->mod_mouse_state |= 2; + break; + case 107: + v->mod_mouse_state &= ~8; + break; + case 108: + v->mod_mouse_state |= 8; + break; + case 109: + v->mod_mouse_state &= ~16; + break; + case 110: + v->mod_mouse_state |= 16; + break; + } + + init_stream(s, 8192); + out_uint8(s, 5); + out_uint8(s, v->mod_mouse_state); + out_uint16_be(s, param1); + out_uint16_be(s, param2); + error = lib_send(v, s->data, 6); + } + else if (msg == 200) /* invalidate */ + { + /* FrambufferUpdateRequest */ + init_stream(s, 8192); + out_uint8(s, 3); + out_uint8(s, 0); + x = (param1 >> 16) & 0xffff; + out_uint16_be(s, x); + y = param1 & 0xffff; + out_uint16_be(s, y); + cx = (param2 >> 16) & 0xffff; + out_uint16_be(s, cx); + cy = param2 & 0xffff; + out_uint16_be(s, cy); + error = lib_send(v, s->data, 10); + } + + free_stream(s); + return error; } //****************************************************************************** int DEFAULT_CC -get_pixel_safe(char* data, int x, int y, int width, int height, int bpp) +get_pixel_safe(char *data, int x, int y, int width, int height, int bpp) { - int start = 0; - int shift = 0; + int start = 0; + int shift = 0; - if (x < 0) - { - return 0; - } - if (y < 0) - { - return 0; - } - if (x >= width) - { - return 0; - } - if (y >= height) - { - return 0; - } - if (bpp == 1) - { - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - return (data[start] & (0x80 >> shift)) != 0; - } - else if (bpp == 4) - { - width = (width + 1) / 2; - start = y * width + x / 2; - shift = x % 2; - if (shift == 0) + if (x < 0) { - return (data[start] & 0xf0) >> 4; + return 0; + } + + if (y < 0) + { + return 0; + } + + if (x >= width) + { + return 0; + } + + if (y >= height) + { + return 0; + } + + if (bpp == 1) + { + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + return (data[start] & (0x80 >> shift)) != 0; + } + else if (bpp == 4) + { + width = (width + 1) / 2; + start = y * width + x / 2; + shift = x % 2; + + if (shift == 0) + { + return (data[start] & 0xf0) >> 4; + } + else + { + return data[start] & 0x0f; + } + } + else if (bpp == 8) + { + return *(((unsigned char *)data) + (y * width + x)); + } + else if (bpp == 15 || bpp == 16) + { + return *(((unsigned short *)data) + (y * width + x)); + } + else if (bpp == 24 || bpp == 32) + { + return *(((unsigned int *)data) + (y * width + x)); } else { - return data[start] & 0x0f; + log_message(LOG_LEVEL_ERROR, "error in get_pixel_safe bpp %d", bpp); } - } - else if (bpp == 8) - { - return *(((unsigned char*)data) + (y * width + x)); - } - else if (bpp == 15 || bpp == 16) - { - return *(((unsigned short*)data) + (y * width + x)); - } - else if (bpp == 24 || bpp == 32) - { - return *(((unsigned int*)data) + (y * width + x)); - } - else - { - log_message(LOG_LEVEL_ERROR, "error in get_pixel_safe bpp %d", bpp); - } - return 0; + + return 0; } /******************************************************************************/ void DEFAULT_CC -set_pixel_safe(char* data, int x, int y, int width, int height, int bpp, +set_pixel_safe(char *data, int x, int y, int width, int height, int bpp, int pixel) { - int start = 0; - int shift = 0; + int start = 0; + int shift = 0; - if (x < 0) - { - return; - } - if (y < 0) - { - return; - } - if (x >= width) - { - return; - } - if (y >= height) - { - return; - } - if (bpp == 1) - { - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - if (pixel & 1) + if (x < 0) { - data[start] = data[start] | (0x80 >> shift); + return; + } + + if (y < 0) + { + return; + } + + if (x >= width) + { + return; + } + + if (y >= height) + { + return; + } + + if (bpp == 1) + { + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + + if (pixel & 1) + { + data[start] = data[start] | (0x80 >> shift); + } + else + { + data[start] = data[start] & ~(0x80 >> shift); + } + } + else if (bpp == 15 || bpp == 16) + { + *(((unsigned short *)data) + (y * width + x)) = pixel; + } + else if (bpp == 24) + { + *(data + (3 * (y * width + x)) + 0) = pixel >> 0; + *(data + (3 * (y * width + x)) + 1) = pixel >> 8; + *(data + (3 * (y * width + x)) + 2) = pixel >> 16; } else { - data[start] = data[start] & ~(0x80 >> shift); + log_message(LOG_LEVEL_ERROR, "error in set_pixel_safe bpp %d", bpp); } - } - else if (bpp == 15 || bpp == 16) - { - *(((unsigned short*)data) + (y * width + x)) = pixel; - } - else if (bpp == 24) - { - *(data + (3 * (y * width + x)) + 0) = pixel >> 0; - *(data + (3 * (y * width + x)) + 1) = pixel >> 8; - *(data + (3 * (y * width + x)) + 2) = pixel >> 16; - } - else - { - log_message(LOG_LEVEL_ERROR, "error in set_pixel_safe bpp %d", bpp); - } } /******************************************************************************/ int DEFAULT_CC -split_color(int pixel, int* r, int* g, int* b, int bpp, int* palette) +split_color(int pixel, int *r, int *g, int *b, int bpp, int *palette) { - if (bpp == 8) - { - if (pixel >= 0 && pixel < 256 && palette != 0) + if (bpp == 8) { - *r = (palette[pixel] >> 16) & 0xff; - *g = (palette[pixel] >> 8) & 0xff; - *b = (palette[pixel] >> 0) & 0xff; + if (pixel >= 0 && pixel < 256 && palette != 0) + { + *r = (palette[pixel] >> 16) & 0xff; + *g = (palette[pixel] >> 8) & 0xff; + *b = (palette[pixel] >> 0) & 0xff; + } } - } - else if (bpp == 15) - { - *r = ((pixel >> 7) & 0xf8) | ((pixel >> 12) & 0x7); - *g = ((pixel >> 2) & 0xf8) | ((pixel >> 8) & 0x7); - *b = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7); - } - else if (bpp == 16) - { - *r = ((pixel >> 8) & 0xf8) | ((pixel >> 13) & 0x7); - *g = ((pixel >> 3) & 0xfc) | ((pixel >> 9) & 0x3); - *b = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7); - } - else if (bpp == 24 || bpp == 32) - { - *r = (pixel >> 16) & 0xff; - *g = (pixel >> 8) & 0xff; - *b = pixel & 0xff; - } - else - { - log_message(LOG_LEVEL_ERROR, "error in split_color bpp %d", bpp); - } - return 0; + else if (bpp == 15) + { + *r = ((pixel >> 7) & 0xf8) | ((pixel >> 12) & 0x7); + *g = ((pixel >> 2) & 0xf8) | ((pixel >> 8) & 0x7); + *b = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7); + } + else if (bpp == 16) + { + *r = ((pixel >> 8) & 0xf8) | ((pixel >> 13) & 0x7); + *g = ((pixel >> 3) & 0xfc) | ((pixel >> 9) & 0x3); + *b = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7); + } + else if (bpp == 24 || bpp == 32) + { + *r = (pixel >> 16) & 0xff; + *g = (pixel >> 8) & 0xff; + *b = pixel & 0xff; + } + else + { + log_message(LOG_LEVEL_ERROR, "error in split_color bpp %d", bpp); + } + + return 0; } /******************************************************************************/ int DEFAULT_CC make_color(int r, int g, int b, int bpp) { - if (bpp == 24) - { - return (r << 16) | (g << 8) | b; - } - else - { - log_message(LOG_LEVEL_ERROR, "error in make_color bpp %d", bpp); - } - return 0; -} - -/******************************************************************************/ -int DEFAULT_CC -lib_framebuffer_update(struct vnc* v) -{ - char* data; - char* d1; - char* d2; - char cursor_data[32 * (32 * 3)]; - char cursor_mask[32 * (32 / 8)]; - char text[256]; - int num_recs; - int i; - int j; - int k; - int x; - int y; - int cx; - int cy; - int srcx; - int srcy; - int encoding; - int Bpp; - int pixel; - int r; - int g; - int b; - int data_size; - int need_size; - int error; - struct stream* s; - - data_size = 0; - data = 0; - num_recs = 0; - Bpp = (v->mod_bpp + 7) / 8; - if (Bpp == 3) - { - Bpp = 4; - } - make_stream(s); - init_stream(s, 8192); - error = lib_recv(v, s->data, 3); - if (error == 0) - { - in_uint8s(s, 1); - in_uint16_be(s, num_recs); - error = v->server_begin_update(v); - } - for (i = 0; i < num_recs; i++) - { - if (error != 0) + if (bpp == 24) { - break; - } - init_stream(s, 8192); - error = lib_recv(v, s->data, 12); - if (error == 0) - { - in_uint16_be(s, x); - in_uint16_be(s, y); - in_uint16_be(s, cx); - in_uint16_be(s, cy); - in_uint32_be(s, encoding); - if (encoding == 0) /* raw */ - { - need_size = cx * cy * Bpp; - if (need_size > data_size) - { - g_free(data); - data = (char*)g_malloc(need_size, 0); - data_size = need_size; - } - error = lib_recv(v, data, need_size); - if (error == 0) - { - error = v->server_paint_rect(v, x, y, cx, cy, data, cx, cy, 0, 0); - } - } - else if (encoding == 1) /* copy rect */ - { - init_stream(s, 8192); - error = lib_recv(v, s->data, 4); - if (error == 0) - { - in_uint16_be(s, srcx); - in_uint16_be(s, srcy); - error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy); - } - } - else if (encoding == 0xffffff11) /* cursor */ - { - g_memset(cursor_data, 0, 32 * (32 * 3)); - g_memset(cursor_mask, 0, 32 * (32 / 8)); - j = cx * cy * Bpp; - k = ((cx + 7) / 8) * cy; - init_stream(s, j + k); - error = lib_recv(v, s->data, j + k); - if (error == 0) - { - in_uint8p(s, d1, j); - in_uint8p(s, d2, k); - for (j = 0; j < 32; j++) - { - for (k = 0; k < 32; k++) - { - pixel = get_pixel_safe(d2, k, 31 - j, cx, cy, 1); - set_pixel_safe(cursor_mask, k, j, 32, 32, 1, !pixel); - if (pixel) - { - pixel = get_pixel_safe(d1, k, 31 - j, cx, cy, v->mod_bpp); - split_color(pixel, &r, &g, &b, v->mod_bpp, v->palette); - pixel = make_color(r, g, b, 24); - set_pixel_safe(cursor_data, k, j, 32, 32, 24, pixel); - } - } - } - /* keep these in 32x32, vnc cursor can be alot bigger */ - if (x > 31) - { - x = 31; - } - if (y > 31) - { - y = 31; - } - error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask); - } - } - else if (encoding == 0xffffff21) /* desktop size */ - { - v->mod_width = cx; - v->mod_height = cy; - error = v->server_reset(v, cx, cy, v->mod_bpp); - } - else - { - g_sprintf(text, "VNC error in lib_framebuffer_update encoding = %8.8x", - encoding); - v->server_msg(v, text, 1); - } - } - } - if (error == 0) - { - error = v->server_end_update(v); - } - g_free(data); - if (error == 0) - { - /* FrambufferUpdateRequest */ - init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 1); - out_uint16_be(s, 0); - out_uint16_be(s, 0); - out_uint16_be(s, v->mod_width); - out_uint16_be(s, v->mod_height); - error = lib_send(v, s->data, 10); - } - free_stream(s); - return error; -} - -/******************************************************************************/ -int DEFAULT_CC -lib_clip_data(struct vnc* v) -{ - struct stream* s; - struct stream* out_s; - int size; - int error; - - g_free(v->clip_data); - v->clip_data = 0; - v->clip_data_size = 0; - make_stream(s); - init_stream(s, 8192); - error = lib_recv(v, s->data, 7); - if (error == 0) - { - in_uint8s(s, 3); - in_uint32_be(s, size); - v->clip_data = (char*)g_malloc(size, 0); - v->clip_data_size = size; - error = lib_recv(v, v->clip_data, size); - } - if (error == 0) - { - make_stream(out_s); - init_stream(out_s, 8192); - out_uint16_le(out_s, 2); - out_uint16_le(out_s, 0); - out_uint32_le(out_s, 0x90); - out_uint8(out_s, 0x0d); - out_uint8s(out_s, 35); - out_uint8(out_s, 0x10); - out_uint8s(out_s, 35); - out_uint8(out_s, 0x01); - out_uint8s(out_s, 35); - out_uint8(out_s, 0x07); - out_uint8s(out_s, 35); - out_uint8s(out_s, 4); - s_mark_end(out_s); - size = (int)(out_s->end - out_s->data); - error = v->server_send_to_channel(v, v->clip_chanid, out_s->data, size, size, 3); - free_stream(out_s); - } - free_stream(s); - return error; -} - -/******************************************************************************/ -int DEFAULT_CC -lib_palette_update(struct vnc* v) -{ - struct stream* s; - int first_color; - int num_colors; - int i; - int r; - int g; - int b; - int error; - - make_stream(s); - init_stream(s, 8192); - error = lib_recv(v, s->data, 5); - if (error == 0) - { - in_uint8s(s, 1); - in_uint16_be(s, first_color); - in_uint16_be(s, num_colors); - init_stream(s, 8192); - error = lib_recv(v, s->data, num_colors * 6); - } - if (error == 0) - { - for (i = 0; i < num_colors; i++) - { - in_uint16_be(s, r); - in_uint16_be(s, g); - in_uint16_be(s, b); - r = r >> 8; - g = g >> 8; - b = b >> 8; - v->palette[first_color + i] = (r << 16) | (g << 8) | b; - } - error = v->server_begin_update(v); - } - if (error == 0) - { - error = v->server_palette(v, v->palette); - } - if (error == 0) - { - error = v->server_end_update(v); - } - free_stream(s); - return error; -} - -/******************************************************************************/ -int DEFAULT_CC -lib_bell_trigger(struct vnc* v) -{ - struct stream* s; - int error; - - error = v->server_bell_trigger(v); - return error; -} - -/******************************************************************************/ -int DEFAULT_CC -lib_mod_signal(struct vnc* v) -{ - char type; - int error; - char text[256]; - - error = lib_recv(v, &type, 1); - if (error == 0) - { - if (type == 0) /* framebuffer update */ - { - error = lib_framebuffer_update(v); - } - else if (type == 1) /* palette */ - { - error = lib_palette_update(v); - } - else if (type == 2) /* bell */ - { - error = lib_bell_trigger(v); - } - else if (type == 3) /* clipboard */ - { - log_message(LOG_LEVEL_DEBUG, "VNC got clip data"); - error = lib_clip_data(v); + return (r << 16) | (g << 8) | b; } else { - g_sprintf(text, "VNC unknown in lib_mod_signal %d", type); - v->server_msg(v, text, 1); + log_message(LOG_LEVEL_ERROR, "error in make_color bpp %d", bpp); } - } - return error; + + return 0; } /******************************************************************************/ int DEFAULT_CC -lib_mod_start(struct vnc* v, int w, int h, int bpp) +lib_framebuffer_update(struct vnc *v) { - v->server_begin_update(v); - v->server_set_fgcolor(v, 0); - v->server_fill_rect(v, 0, 0, w, h); - v->server_end_update(v); - v->server_width = w; - v->server_height = h; - v->server_bpp = bpp; - return 0; + char *data; + char *d1; + char *d2; + char cursor_data[32 * (32 * 3)]; + char cursor_mask[32 * (32 / 8)]; + char text[256]; + int num_recs; + int i; + int j; + int k; + int x; + int y; + int cx; + int cy; + int srcx; + int srcy; + int encoding; + int Bpp; + int pixel; + int r; + int g; + int b; + int data_size; + int need_size; + int error; + struct stream *s; + + data_size = 0; + data = 0; + num_recs = 0; + Bpp = (v->mod_bpp + 7) / 8; + + if (Bpp == 3) + { + Bpp = 4; + } + + make_stream(s); + init_stream(s, 8192); + error = lib_recv(v, s->data, 3); + + if (error == 0) + { + in_uint8s(s, 1); + in_uint16_be(s, num_recs); + error = v->server_begin_update(v); + } + + for (i = 0; i < num_recs; i++) + { + if (error != 0) + { + break; + } + + init_stream(s, 8192); + error = lib_recv(v, s->data, 12); + + if (error == 0) + { + in_uint16_be(s, x); + in_uint16_be(s, y); + in_uint16_be(s, cx); + in_uint16_be(s, cy); + in_uint32_be(s, encoding); + + if (encoding == 0) /* raw */ + { + need_size = cx * cy * Bpp; + + if (need_size > data_size) + { + g_free(data); + data = (char *)g_malloc(need_size, 0); + data_size = need_size; + } + + error = lib_recv(v, data, need_size); + + if (error == 0) + { + error = v->server_paint_rect(v, x, y, cx, cy, data, cx, cy, 0, 0); + } + } + else if (encoding == 1) /* copy rect */ + { + init_stream(s, 8192); + error = lib_recv(v, s->data, 4); + + if (error == 0) + { + in_uint16_be(s, srcx); + in_uint16_be(s, srcy); + error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy); + } + } + else if (encoding == 0xffffff11) /* cursor */ + { + g_memset(cursor_data, 0, 32 * (32 * 3)); + g_memset(cursor_mask, 0, 32 * (32 / 8)); + j = cx * cy * Bpp; + k = ((cx + 7) / 8) * cy; + init_stream(s, j + k); + error = lib_recv(v, s->data, j + k); + + if (error == 0) + { + in_uint8p(s, d1, j); + in_uint8p(s, d2, k); + + for (j = 0; j < 32; j++) + { + for (k = 0; k < 32; k++) + { + pixel = get_pixel_safe(d2, k, 31 - j, cx, cy, 1); + set_pixel_safe(cursor_mask, k, j, 32, 32, 1, !pixel); + + if (pixel) + { + pixel = get_pixel_safe(d1, k, 31 - j, cx, cy, v->mod_bpp); + split_color(pixel, &r, &g, &b, v->mod_bpp, v->palette); + pixel = make_color(r, g, b, 24); + set_pixel_safe(cursor_data, k, j, 32, 32, 24, pixel); + } + } + } + + /* keep these in 32x32, vnc cursor can be alot bigger */ + if (x > 31) + { + x = 31; + } + + if (y > 31) + { + y = 31; + } + + error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask); + } + } + else if (encoding == 0xffffff21) /* desktop size */ + { + v->mod_width = cx; + v->mod_height = cy; + error = v->server_reset(v, cx, cy, v->mod_bpp); + } + else + { + g_sprintf(text, "VNC error in lib_framebuffer_update encoding = %8.8x", + encoding); + v->server_msg(v, text, 1); + } + } + } + + if (error == 0) + { + error = v->server_end_update(v); + } + + g_free(data); + + if (error == 0) + { + /* FrambufferUpdateRequest */ + init_stream(s, 8192); + out_uint8(s, 3); + out_uint8(s, 1); + out_uint16_be(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, v->mod_width); + out_uint16_be(s, v->mod_height); + error = lib_send(v, s->data, 10); + } + + free_stream(s); + return error; +} + +/******************************************************************************/ +int DEFAULT_CC +lib_clip_data(struct vnc *v) +{ + struct stream *s; + struct stream *out_s; + int size; + int error; + + g_free(v->clip_data); + v->clip_data = 0; + v->clip_data_size = 0; + make_stream(s); + init_stream(s, 8192); + error = lib_recv(v, s->data, 7); + + if (error == 0) + { + in_uint8s(s, 3); + in_uint32_be(s, size); + v->clip_data = (char *)g_malloc(size, 0); + v->clip_data_size = size; + error = lib_recv(v, v->clip_data, size); + } + + if (error == 0) + { + make_stream(out_s); + init_stream(out_s, 8192); + out_uint16_le(out_s, 2); + out_uint16_le(out_s, 0); + out_uint32_le(out_s, 0x90); + out_uint8(out_s, 0x0d); + out_uint8s(out_s, 35); + out_uint8(out_s, 0x10); + out_uint8s(out_s, 35); + out_uint8(out_s, 0x01); + out_uint8s(out_s, 35); + out_uint8(out_s, 0x07); + out_uint8s(out_s, 35); + out_uint8s(out_s, 4); + s_mark_end(out_s); + size = (int)(out_s->end - out_s->data); + error = v->server_send_to_channel(v, v->clip_chanid, out_s->data, size, size, 3); + free_stream(out_s); + } + + free_stream(s); + return error; +} + +/******************************************************************************/ +int DEFAULT_CC +lib_palette_update(struct vnc *v) +{ + struct stream *s; + int first_color; + int num_colors; + int i; + int r; + int g; + int b; + int error; + + make_stream(s); + init_stream(s, 8192); + error = lib_recv(v, s->data, 5); + + if (error == 0) + { + in_uint8s(s, 1); + in_uint16_be(s, first_color); + in_uint16_be(s, num_colors); + init_stream(s, 8192); + error = lib_recv(v, s->data, num_colors * 6); + } + + if (error == 0) + { + for (i = 0; i < num_colors; i++) + { + in_uint16_be(s, r); + in_uint16_be(s, g); + in_uint16_be(s, b); + r = r >> 8; + g = g >> 8; + b = b >> 8; + v->palette[first_color + i] = (r << 16) | (g << 8) | b; + } + + error = v->server_begin_update(v); + } + + if (error == 0) + { + error = v->server_palette(v, v->palette); + } + + if (error == 0) + { + error = v->server_end_update(v); + } + + free_stream(s); + return error; +} + +/******************************************************************************/ +int DEFAULT_CC +lib_bell_trigger(struct vnc *v) +{ + struct stream *s; + int error; + + error = v->server_bell_trigger(v); + return error; +} + +/******************************************************************************/ +int DEFAULT_CC +lib_mod_signal(struct vnc *v) +{ + char type; + int error; + char text[256]; + + error = lib_recv(v, &type, 1); + + if (error == 0) + { + if (type == 0) /* framebuffer update */ + { + error = lib_framebuffer_update(v); + } + else if (type == 1) /* palette */ + { + error = lib_palette_update(v); + } + else if (type == 2) /* bell */ + { + error = lib_bell_trigger(v); + } + else if (type == 3) /* clipboard */ + { + log_message(LOG_LEVEL_DEBUG, "VNC got clip data"); + error = lib_clip_data(v); + } + else + { + g_sprintf(text, "VNC unknown in lib_mod_signal %d", type); + v->server_msg(v, text, 1); + } + } + + return error; +} + +/******************************************************************************/ +int DEFAULT_CC +lib_mod_start(struct vnc *v, int w, int h, int bpp) +{ + v->server_begin_update(v); + v->server_set_fgcolor(v, 0); + v->server_fill_rect(v, 0, 0, w, h); + v->server_end_update(v); + v->server_width = w; + v->server_height = h; + v->server_bpp = bpp; + return 0; } /******************************************************************************/ static int APP_CC -lib_open_clip_channel(struct vnc* v) +lib_open_clip_channel(struct vnc *v) { - char init_data[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + char init_data[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - v->clip_chanid = v->server_get_channel_id(v, "cliprdr"); - if (v->clip_chanid >= 0) - { - v->server_send_to_channel(v, v->clip_chanid, init_data, 12, 12, 3); - } - return 0; + v->clip_chanid = v->server_get_channel_id(v, "cliprdr"); + + if (v->clip_chanid >= 0) + { + v->server_send_to_channel(v, v->clip_chanid, init_data, 12, 12, 3); + } + + return 0; } /******************************************************************************/ @@ -841,440 +934,478 @@ lib_open_clip_channel(struct vnc* v) return error */ int DEFAULT_CC -lib_mod_connect(struct vnc* v) +lib_mod_connect(struct vnc *v) { - char cursor_data[32 * (32 * 3)]; - char cursor_mask[32 * (32 / 8)]; - char con_port[256]; - char text[256]; - struct stream* s; - struct stream* pixel_format; - int error; - int i; - int check_sec_result; + char cursor_data[32 * (32 * 3)]; + char cursor_mask[32 * (32 / 8)]; + char con_port[256]; + char text[256]; + struct stream *s; + struct stream *pixel_format; + int error; + int i; + int check_sec_result; - v->server_msg(v, "VNC started connecting", 0); - check_sec_result = 1; - /* only support 8 and 16 bpp connections from rdp client */ - if ((v->server_bpp != 8) && (v->server_bpp != 15) && - (v->server_bpp != 16) && (v->server_bpp != 24)) - { - v->server_msg(v, "VNC error - only supporting 8, 15, 16 and 24 bpp rdp " - "connections", 0); - return 1; - } - if (g_strcmp(v->ip, "") == 0) - { - v->server_msg(v, "VNC error - no ip set", 0); - return 1; - } - make_stream(s); - g_sprintf(con_port, "%s", v->port); - make_stream(pixel_format); - v->sck = g_tcp_socket(); - v->sck_obj = g_create_wait_obj_from_socket(v->sck, 0); - v->sck_closed = 0; - g_sprintf(text, "VNC connecting to %s %s", v->ip, con_port); - v->server_msg(v, text, 0); - error = g_tcp_connect(v->sck, v->ip, con_port); - if (error == 0) - { - v->server_msg(v, "VNC tcp connected", 0); - g_tcp_set_non_blocking(v->sck); - g_tcp_set_no_delay(v->sck); - /* protocal version */ - init_stream(s, 8192); - error = lib_recv(v, s->data, 12); - if (error == 0) + v->server_msg(v, "VNC started connecting", 0); + check_sec_result = 1; + + /* only support 8 and 16 bpp connections from rdp client */ + if ((v->server_bpp != 8) && (v->server_bpp != 15) && + (v->server_bpp != 16) && (v->server_bpp != 24)) { - error = lib_send(v, "RFB 003.003\n", 12); + v->server_msg(v, "VNC error - only supporting 8, 15, 16 and 24 bpp rdp " + "connections", 0); + return 1; } - /* sec type */ - if (error == 0) + + if (g_strcmp(v->ip, "") == 0) { - init_stream(s, 8192); - error = lib_recv(v, s->data, 4); + v->server_msg(v, "VNC error - no ip set", 0); + return 1; } + + make_stream(s); + g_sprintf(con_port, "%s", v->port); + make_stream(pixel_format); + v->sck = g_tcp_socket(); + v->sck_obj = g_create_wait_obj_from_socket(v->sck, 0); + v->sck_closed = 0; + g_sprintf(text, "VNC connecting to %s %s", v->ip, con_port); + v->server_msg(v, text, 0); + error = g_tcp_connect(v->sck, v->ip, con_port); + if (error == 0) { - in_uint32_be(s, i); - g_sprintf(text, "VNC security level is %d (1 = none, 2 = standard)", i); - v->server_msg(v, text, 0); - if (i == 1) /* none */ - { - check_sec_result = 0; - } - else if (i == 2) /* dec the password and the server random */ - { + v->server_msg(v, "VNC tcp connected", 0); + g_tcp_set_non_blocking(v->sck); + g_tcp_set_no_delay(v->sck); + /* protocal version */ init_stream(s, 8192); - error = lib_recv(v, s->data, 16); + error = lib_recv(v, s->data, 12); + if (error == 0) { - rfbEncryptBytes(s->data, v->password); - error = lib_send(v, s->data, 16); - check_sec_result = 1; // not needed + error = lib_send(v, "RFB 003.003\n", 12); + } + + /* sec type */ + if (error == 0) + { + init_stream(s, 8192); + error = lib_recv(v, s->data, 4); + } + + if (error == 0) + { + in_uint32_be(s, i); + g_sprintf(text, "VNC security level is %d (1 = none, 2 = standard)", i); + v->server_msg(v, text, 0); + + if (i == 1) /* none */ + { + check_sec_result = 0; + } + else if (i == 2) /* dec the password and the server random */ + { + init_stream(s, 8192); + error = lib_recv(v, s->data, 16); + + if (error == 0) + { + rfbEncryptBytes(s->data, v->password); + error = lib_send(v, s->data, 16); + check_sec_result = 1; // not needed + } + } + else if (i == 0) + { + log_message(LOG_LEVEL_DEBUG, "VNC Server will disconnect"); + error = 1; + } + else + { + log_message(LOG_LEVEL_DEBUG, "VNC unsupported security level"); + error = 1; + } } - } - else if (i == 0) - { - log_message(LOG_LEVEL_DEBUG, "VNC Server will disconnect"); - error = 1; - } - else - { - log_message(LOG_LEVEL_DEBUG, "VNC unsupported security level"); - error = 1; - } } - } - if (error!=0) - { - log_message(LOG_LEVEL_DEBUG, "VNC Error after security negotiation"); - } - if (error == 0 && check_sec_result) - { - /* sec result */ - init_stream(s, 8192); - error = lib_recv(v, s->data, 4); + + if (error != 0) + { + log_message(LOG_LEVEL_DEBUG, "VNC Error after security negotiation"); + } + + if (error == 0 && check_sec_result) + { + /* sec result */ + init_stream(s, 8192); + error = lib_recv(v, s->data, 4); + + if (error == 0) + { + in_uint32_be(s, i); + + if (i != 0) + { + v->server_msg(v, "VNC password failed", 0); + error = 2; + } + else + { + v->server_msg(v, "VNC password ok", 0); + } + } + } + if (error == 0) { - in_uint32_be(s, i); - if (i != 0) - { - v->server_msg(v, "VNC password failed", 0); - error = 2; - } - else - { - v->server_msg(v, "VNC password ok", 0); - } - } - } - if (error == 0) - { - v->server_msg(v, "VNC sending share flag", 0); - init_stream(s, 8192); - s->data[0] = 1; - error = lib_send(v, s->data, 1); /* share flag */ - } - else - { - log_message(LOG_LEVEL_DEBUG, "VNC error before sending share flag"); - } - if (error == 0) - { - v->server_msg(v, "VNC receiving server init", 0); - error = lib_recv(v, s->data, 4); /* server init */ - } - else - { - log_message(LOG_LEVEL_DEBUG, "VNC error before receiving server init"); - } - if (error == 0) - { - in_uint16_be(s, v->mod_width); - in_uint16_be(s, v->mod_height); - init_stream(pixel_format, 8192); - v->server_msg(v, "VNC receiving pixel format", 0); - error = lib_recv(v, pixel_format->data, 16); - } - else - { - log_message(LOG_LEVEL_DEBUG, "VNC error before receiving pixel format"); - } - if (error == 0) - { - v->mod_bpp = v->server_bpp; - init_stream(s, 8192); - v->server_msg(v, "VNC receiving name length", 0); - error = lib_recv(v, s->data, 4); /* name len */ - } - else - { - log_message(LOG_LEVEL_DEBUG, "VNC error before receiving name length"); - } - if (error == 0) - { - in_uint32_be(s, i); - if (i > 255 || i < 0) - { - error = 3; + v->server_msg(v, "VNC sending share flag", 0); + init_stream(s, 8192); + s->data[0] = 1; + error = lib_send(v, s->data, 1); /* share flag */ } else { - v->server_msg(v, "VNC receiving name", 0); - error = lib_recv(v, v->mod_name, i); - v->mod_name[i] = 0; + log_message(LOG_LEVEL_DEBUG, "VNC error before sending share flag"); } - } - else - { - log_message(LOG_LEVEL_DEBUG, "VNC error before receiving name"); - } - /* should be connected */ - if (error == 0) - { - /* SetPixelFormat */ - init_stream(s, 8192); - out_uint8(s, 0); - out_uint8(s, 0); - out_uint8(s, 0); - out_uint8(s, 0); - init_stream(pixel_format, 8192); - if (v->mod_bpp == 8) + + if (error == 0) { - out_uint8(pixel_format, 8); /* bits per pixel */ - out_uint8(pixel_format, 8); /* depth */ + v->server_msg(v, "VNC receiving server init", 0); + error = lib_recv(v, s->data, 4); /* server init */ + } + else + { + log_message(LOG_LEVEL_DEBUG, "VNC error before receiving server init"); + } + + if (error == 0) + { + in_uint16_be(s, v->mod_width); + in_uint16_be(s, v->mod_height); + init_stream(pixel_format, 8192); + v->server_msg(v, "VNC receiving pixel format", 0); + error = lib_recv(v, pixel_format->data, 16); + } + else + { + log_message(LOG_LEVEL_DEBUG, "VNC error before receiving pixel format"); + } + + if (error == 0) + { + v->mod_bpp = v->server_bpp; + init_stream(s, 8192); + v->server_msg(v, "VNC receiving name length", 0); + error = lib_recv(v, s->data, 4); /* name len */ + } + else + { + log_message(LOG_LEVEL_DEBUG, "VNC error before receiving name length"); + } + + if (error == 0) + { + in_uint32_be(s, i); + + if (i > 255 || i < 0) + { + error = 3; + } + else + { + v->server_msg(v, "VNC receiving name", 0); + error = lib_recv(v, v->mod_name, i); + v->mod_name[i] = 0; + } + } + else + { + log_message(LOG_LEVEL_DEBUG, "VNC error before receiving name"); + } + + /* should be connected */ + if (error == 0) + { + /* SetPixelFormat */ + init_stream(s, 8192); + out_uint8(s, 0); + out_uint8(s, 0); + out_uint8(s, 0); + out_uint8(s, 0); + init_stream(pixel_format, 8192); + + if (v->mod_bpp == 8) + { + out_uint8(pixel_format, 8); /* bits per pixel */ + out_uint8(pixel_format, 8); /* depth */ #if defined(B_ENDIAN) - out_uint8(pixel_format, 1); /* big endian */ + out_uint8(pixel_format, 1); /* big endian */ #else - out_uint8(pixel_format, 0); /* big endian */ + out_uint8(pixel_format, 0); /* big endian */ #endif - out_uint8(pixel_format, 0); /* true color flag */ - out_uint16_be(pixel_format, 0); /* red max */ - out_uint16_be(pixel_format, 0); /* green max */ - out_uint16_be(pixel_format, 0); /* blue max */ - out_uint8(pixel_format, 0); /* red shift */ - out_uint8(pixel_format, 0); /* green shift */ - out_uint8(pixel_format, 0); /* blue shift */ - out_uint8s(pixel_format, 3); /* pad */ - } - else if (v->mod_bpp == 15) - { - out_uint8(pixel_format, 16); /* bits per pixel */ - out_uint8(pixel_format, 15); /* depth */ + out_uint8(pixel_format, 0); /* true color flag */ + out_uint16_be(pixel_format, 0); /* red max */ + out_uint16_be(pixel_format, 0); /* green max */ + out_uint16_be(pixel_format, 0); /* blue max */ + out_uint8(pixel_format, 0); /* red shift */ + out_uint8(pixel_format, 0); /* green shift */ + out_uint8(pixel_format, 0); /* blue shift */ + out_uint8s(pixel_format, 3); /* pad */ + } + else if (v->mod_bpp == 15) + { + out_uint8(pixel_format, 16); /* bits per pixel */ + out_uint8(pixel_format, 15); /* depth */ #if defined(B_ENDIAN) - out_uint8(pixel_format, 1); /* big endian */ + out_uint8(pixel_format, 1); /* big endian */ #else - out_uint8(pixel_format, 0); /* big endian */ + out_uint8(pixel_format, 0); /* big endian */ #endif - out_uint8(pixel_format, 1); /* true color flag */ - out_uint16_be(pixel_format, 31); /* red max */ - out_uint16_be(pixel_format, 31); /* green max */ - out_uint16_be(pixel_format, 31); /* blue max */ - out_uint8(pixel_format, 10); /* red shift */ - out_uint8(pixel_format, 5); /* green shift */ - out_uint8(pixel_format, 0); /* blue shift */ - out_uint8s(pixel_format, 3); /* pad */ - } - else if (v->mod_bpp == 16) - { - out_uint8(pixel_format, 16); /* bits per pixel */ - out_uint8(pixel_format, 16); /* depth */ + out_uint8(pixel_format, 1); /* true color flag */ + out_uint16_be(pixel_format, 31); /* red max */ + out_uint16_be(pixel_format, 31); /* green max */ + out_uint16_be(pixel_format, 31); /* blue max */ + out_uint8(pixel_format, 10); /* red shift */ + out_uint8(pixel_format, 5); /* green shift */ + out_uint8(pixel_format, 0); /* blue shift */ + out_uint8s(pixel_format, 3); /* pad */ + } + else if (v->mod_bpp == 16) + { + out_uint8(pixel_format, 16); /* bits per pixel */ + out_uint8(pixel_format, 16); /* depth */ #if defined(B_ENDIAN) - out_uint8(pixel_format, 1); /* big endian */ + out_uint8(pixel_format, 1); /* big endian */ #else - out_uint8(pixel_format, 0); /* big endian */ + out_uint8(pixel_format, 0); /* big endian */ #endif - out_uint8(pixel_format, 1); /* true color flag */ - out_uint16_be(pixel_format, 31); /* red max */ - out_uint16_be(pixel_format, 63); /* green max */ - out_uint16_be(pixel_format, 31); /* blue max */ - out_uint8(pixel_format, 11); /* red shift */ - out_uint8(pixel_format, 5); /* green shift */ - out_uint8(pixel_format, 0); /* blue shift */ - out_uint8s(pixel_format, 3); /* pad */ - } - else if (v->mod_bpp == 24) - { - out_uint8(pixel_format, 32); /* bits per pixel */ - out_uint8(pixel_format, 24); /* depth */ + out_uint8(pixel_format, 1); /* true color flag */ + out_uint16_be(pixel_format, 31); /* red max */ + out_uint16_be(pixel_format, 63); /* green max */ + out_uint16_be(pixel_format, 31); /* blue max */ + out_uint8(pixel_format, 11); /* red shift */ + out_uint8(pixel_format, 5); /* green shift */ + out_uint8(pixel_format, 0); /* blue shift */ + out_uint8s(pixel_format, 3); /* pad */ + } + else if (v->mod_bpp == 24) + { + out_uint8(pixel_format, 32); /* bits per pixel */ + out_uint8(pixel_format, 24); /* depth */ #if defined(B_ENDIAN) - out_uint8(pixel_format, 1); /* big endian */ + out_uint8(pixel_format, 1); /* big endian */ #else - out_uint8(pixel_format, 0); /* big endian */ + out_uint8(pixel_format, 0); /* big endian */ #endif - out_uint8(pixel_format, 1); /* true color flag */ - out_uint16_be(pixel_format, 255); /* red max */ - out_uint16_be(pixel_format, 255); /* green max */ - out_uint16_be(pixel_format, 255); /* blue max */ - out_uint8(pixel_format, 16); /* red shift */ - out_uint8(pixel_format, 8); /* green shift */ - out_uint8(pixel_format, 0); /* blue shift */ - out_uint8s(pixel_format, 3); /* pad */ + out_uint8(pixel_format, 1); /* true color flag */ + out_uint16_be(pixel_format, 255); /* red max */ + out_uint16_be(pixel_format, 255); /* green max */ + out_uint16_be(pixel_format, 255); /* blue max */ + out_uint8(pixel_format, 16); /* red shift */ + out_uint8(pixel_format, 8); /* green shift */ + out_uint8(pixel_format, 0); /* blue shift */ + out_uint8s(pixel_format, 3); /* pad */ + } + + out_uint8a(s, pixel_format->data, 16); + v->server_msg(v, "VNC sending pixel format", 0); + error = lib_send(v, s->data, 20); } - out_uint8a(s, pixel_format->data, 16); - v->server_msg(v, "VNC sending pixel format", 0); - error = lib_send(v, s->data, 20); - } - if (error == 0) - { - /* SetEncodings */ - init_stream(s, 8192); - out_uint8(s, 2); - out_uint8(s, 0); - out_uint16_be(s, 4); - out_uint32_be(s, 0); /* raw */ - out_uint32_be(s, 1); /* copy rect */ - out_uint32_be(s, 0xffffff11); /* cursor */ - out_uint32_be(s, 0xffffff21); /* desktop size */ - v->server_msg(v, "VNC sending encodings", 0); - error = lib_send(v, s->data, 4 + 4 * 4); - } - if (error == 0) - { - error = v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp); - } - if (error == 0) - { - /* FrambufferUpdateRequest */ - init_stream(s, 8192); - out_uint8(s, 3); - out_uint8(s, 0); - out_uint16_be(s, 0); - out_uint16_be(s, 0); - out_uint16_be(s, v->mod_width); - out_uint16_be(s, v->mod_height); - v->server_msg(v, "VNC sending framebuffer update request", 0); - error = lib_send(v, s->data, 10); - } - if (error == 0) - { - if (v->server_bpp != v->mod_bpp) + + if (error == 0) { - v->server_msg(v, "VNC error - server bpp and client bpp do not match", 0); - error = 1; + /* SetEncodings */ + init_stream(s, 8192); + out_uint8(s, 2); + out_uint8(s, 0); + out_uint16_be(s, 4); + out_uint32_be(s, 0); /* raw */ + out_uint32_be(s, 1); /* copy rect */ + out_uint32_be(s, 0xffffff11); /* cursor */ + out_uint32_be(s, 0xffffff21); /* desktop size */ + v->server_msg(v, "VNC sending encodings", 0); + error = lib_send(v, s->data, 4 + 4 * 4); } - } - if (error == 0) - { - /* set almost null cursor, this is the little dot cursor */ - g_memset(cursor_data, 0, 32 * (32 * 3)); - g_memset(cursor_data + (32 * (32 * 3) - 1 * 32 * 3), 0xff, 9); - g_memset(cursor_data + (32 * (32 * 3) - 2 * 32 * 3), 0xff, 9); - g_memset(cursor_data + (32 * (32 * 3) - 3 * 32 * 3), 0xff, 9); - g_memset(cursor_mask, 0xff, 32 * (32 / 8)); - v->server_msg(v, "VNC sending cursor", 0); - error = v->server_set_cursor(v, 3, 3, cursor_data, cursor_mask); - } - free_stream(s); - free_stream(pixel_format); - if (error == 0) - { - v->server_msg(v, "VNC connection complete, connected ok", 0); - lib_open_clip_channel(v); - } - else - { - v->server_msg(v, "VNC error - problem connecting", 0); - } - return error; + + if (error == 0) + { + error = v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp); + } + + if (error == 0) + { + /* FrambufferUpdateRequest */ + init_stream(s, 8192); + out_uint8(s, 3); + out_uint8(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, 0); + out_uint16_be(s, v->mod_width); + out_uint16_be(s, v->mod_height); + v->server_msg(v, "VNC sending framebuffer update request", 0); + error = lib_send(v, s->data, 10); + } + + if (error == 0) + { + if (v->server_bpp != v->mod_bpp) + { + v->server_msg(v, "VNC error - server bpp and client bpp do not match", 0); + error = 1; + } + } + + if (error == 0) + { + /* set almost null cursor, this is the little dot cursor */ + g_memset(cursor_data, 0, 32 * (32 * 3)); + g_memset(cursor_data + (32 * (32 * 3) - 1 * 32 * 3), 0xff, 9); + g_memset(cursor_data + (32 * (32 * 3) - 2 * 32 * 3), 0xff, 9); + g_memset(cursor_data + (32 * (32 * 3) - 3 * 32 * 3), 0xff, 9); + g_memset(cursor_mask, 0xff, 32 * (32 / 8)); + v->server_msg(v, "VNC sending cursor", 0); + error = v->server_set_cursor(v, 3, 3, cursor_data, cursor_mask); + } + + free_stream(s); + free_stream(pixel_format); + + if (error == 0) + { + v->server_msg(v, "VNC connection complete, connected ok", 0); + lib_open_clip_channel(v); + } + else + { + v->server_msg(v, "VNC error - problem connecting", 0); + } + + return error; } /******************************************************************************/ int DEFAULT_CC -lib_mod_end(struct vnc* v) +lib_mod_end(struct vnc *v) { - if (v->vnc_desktop != 0) - { - } - g_free(v->clip_data); - v->clip_data = 0; - v->clip_data_size = 0; - return 0; + if (v->vnc_desktop != 0) + { + } + + g_free(v->clip_data); + v->clip_data = 0; + v->clip_data_size = 0; + return 0; } /******************************************************************************/ int DEFAULT_CC -lib_mod_set_param(struct vnc* v, char* name, char* value) +lib_mod_set_param(struct vnc *v, char *name, char *value) { - if (g_strcasecmp(name, "username") == 0) - { - g_strncpy(v->username, value, 255); - } - else if (g_strcasecmp(name, "password") == 0) - { - g_strncpy(v->password, value, 255); - } - else if (g_strcasecmp(name, "ip") == 0) - { - g_strncpy(v->ip, value, 255); - } - else if (g_strcasecmp(name, "port") == 0) - { - g_strncpy(v->port, value, 255); - } - else if (g_strcasecmp(name, "keylayout") == 0) - { - v->keylayout = g_atoi(value); - } - return 0; + if (g_strcasecmp(name, "username") == 0) + { + g_strncpy(v->username, value, 255); + } + else if (g_strcasecmp(name, "password") == 0) + { + g_strncpy(v->password, value, 255); + } + else if (g_strcasecmp(name, "ip") == 0) + { + g_strncpy(v->ip, value, 255); + } + else if (g_strcasecmp(name, "port") == 0) + { + g_strncpy(v->port, value, 255); + } + else if (g_strcasecmp(name, "keylayout") == 0) + { + v->keylayout = g_atoi(value); + } + + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_get_wait_objs(struct vnc* v, tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout) +lib_mod_get_wait_objs(struct vnc *v, tbus *read_objs, int *rcount, + tbus *write_objs, int *wcount, int *timeout) { - int i; + int i; - i = *rcount; - if (v != 0) - { - if (v->sck_obj != 0) + i = *rcount; + + if (v != 0) { - read_objs[i++] = v->sck_obj; + if (v->sck_obj != 0) + { + read_objs[i++] = v->sck_obj; + } } - } - *rcount = i; - return 0; + + *rcount = i; + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_check_wait_objs(struct vnc* v) +lib_mod_check_wait_objs(struct vnc *v) { - int rv; + int rv; - rv = 0; - if (v != 0) - { - if (v->sck_obj != 0) + rv = 0; + + if (v != 0) { - if (g_is_wait_obj_set(v->sck_obj)) - { - rv = lib_mod_signal(v); - } + if (v->sck_obj != 0) + { + if (g_is_wait_obj_set(v->sck_obj)) + { + rv = lib_mod_signal(v); + } + } } - } - return rv; + + return rv; } /******************************************************************************/ -struct vnc* EXPORT_CC +struct vnc *EXPORT_CC mod_init(void) { - struct vnc* v; + struct vnc *v; - v = (struct vnc*)g_malloc(sizeof(struct vnc), 1); - /* set client functions */ - v->size = sizeof(struct vnc); - v->version = CURRENT_MOD_VER; - v->handle = (long)v; - v->mod_connect = lib_mod_connect; - v->mod_start = lib_mod_start; - v->mod_event = lib_mod_event; - v->mod_signal = lib_mod_signal; - v->mod_end = lib_mod_end; - v->mod_set_param = lib_mod_set_param; - v->mod_get_wait_objs = lib_mod_get_wait_objs; - v->mod_check_wait_objs = lib_mod_check_wait_objs; - return v; + v = (struct vnc *)g_malloc(sizeof(struct vnc), 1); + /* set client functions */ + v->size = sizeof(struct vnc); + v->version = CURRENT_MOD_VER; + v->handle = (long)v; + v->mod_connect = lib_mod_connect; + v->mod_start = lib_mod_start; + v->mod_event = lib_mod_event; + v->mod_signal = lib_mod_signal; + v->mod_end = lib_mod_end; + v->mod_set_param = lib_mod_set_param; + v->mod_get_wait_objs = lib_mod_get_wait_objs; + v->mod_check_wait_objs = lib_mod_check_wait_objs; + return v; } /******************************************************************************/ int EXPORT_CC -mod_exit(struct vnc* v) +mod_exit(struct vnc *v) { - log_message(LOG_LEVEL_DEBUG, "VNC mod_exit"); - if (v == 0) - { + log_message(LOG_LEVEL_DEBUG, "VNC mod_exit"); + + if (v == 0) + { + return 0; + } + + g_delete_wait_obj_from_socket(v->sck_obj); + g_tcp_close(v->sck); + g_free(v); return 0; - } - g_delete_wait_obj_from_socket(v->sck_obj); - g_tcp_close(v->sck); - g_free(v); - return 0; } diff --git a/vnc/vnc.h b/vnc/vnc.h index b9886be4..94d29a30 100644 --- a/vnc/vnc.h +++ b/vnc/vnc.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - libvnc - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * libvnc + */ /* include other h files */ #include "arch.h" diff --git a/xorg/X11R7.6/buildx.sh b/xorg/X11R7.6/buildx.sh index 279f72cb..5a593f1a 100755 --- a/xorg/X11R7.6/buildx.sh +++ b/xorg/X11R7.6/buildx.sh @@ -1,6 +1,7 @@ #!/bin/sh -# build.sh: a script for building X11R7.6 X server for use with xrdp # +# buildx.sh: a script for building X11R7.6 X server for use with xrdp +# # Copyright 2011-2012 Jay Sorg Jay.Sorg@gmail.com # # Authors @@ -26,7 +27,7 @@ download_file() { file=$1 - # if we already have the file, don't re-download it + # if we already have the file, don't download it if [ -r downloads/$file ]; then return 0 fi @@ -277,10 +278,10 @@ count=0 if [ $# -lt 1 ]; then echo "" - echo "usage: build.sh " - echo "usage: build.sh " - echo "usage: build.sh default" - echo "usage: build.sh drop - set env and run bash in rdp dir" + echo "usage: buildx.sh " + echo "usage: buildx.sh " + echo "usage: buildx.sh default" + echo "usage: buildx.sh drop - set env and run bash in rdp dir" echo "" exit 1 fi diff --git a/xorg/X11R7.6/rdp/rdpCopyArea.c b/xorg/X11R7.6/rdp/rdpCopyArea.c index 4b35d9fb..cc4d0fe4 100644 --- a/xorg/X11R7.6/rdp/rdpCopyArea.c +++ b/xorg/X11R7.6/rdp/rdpCopyArea.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -49,14 +49,14 @@ static RegionPtr rdpCopyAreaOrg(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { - rdpGCPtr priv; - GCFuncs* oldFuncs; - RegionPtr rv; + rdpGCPtr priv; + GCFuncs *oldFuncs; + RegionPtr rv; - GC_OP_PROLOGUE(pGC); - rv = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); - GC_OP_EPILOGUE(pGC); - return rv; + GC_OP_PROLOGUE(pGC); + rv = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); + GC_OP_EPILOGUE(pGC); + return rv; } /******************************************************************************/ @@ -65,262 +65,282 @@ rdpCopyAreaWndToWnd(WindowPtr pSrcWnd, WindowPtr pDstWnd, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { - int cd; - int lsrcx; - int lsrcy; - int ldstx; - int ldsty; - int num_clips; - int dx; - int dy; - int j; - BoxRec box; - RegionPtr rv; - RegionRec clip_reg; + int cd; + int lsrcx; + int lsrcy; + int ldstx; + int ldsty; + int num_clips; + int dx; + int dy; + int j; + BoxRec box; + RegionPtr rv; + RegionRec clip_reg; - LLOGLN(10, ("rdpCopyAreaWndToWnd:")); + LLOGLN(10, ("rdpCopyAreaWndToWnd:")); - rv = rdpCopyAreaOrg(&(pSrcWnd->drawable), &(pDstWnd->drawable), - pGC, srcx, srcy, w, h, dstx, dsty); - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, &(pDstWnd->drawable), pGC); - lsrcx = pSrcWnd->drawable.x + srcx; - lsrcy = pSrcWnd->drawable.y + srcy; - ldstx = pDstWnd->drawable.x + dstx; - ldsty = pDstWnd->drawable.y + dsty; - if (cd == 1) - { - rdpup_begin_update(); - rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); - rdpup_end_update(); - } - else if (cd == 2) - { - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) + rv = rdpCopyAreaOrg(&(pSrcWnd->drawable), &(pDstWnd->drawable), + pGC, srcx, srcy, w, h, dstx, dsty); + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, &(pDstWnd->drawable), pGC); + lsrcx = pSrcWnd->drawable.x + srcx; + lsrcy = pSrcWnd->drawable.y + srcy; + ldstx = pDstWnd->drawable.x + dstx; + ldsty = pDstWnd->drawable.y + dsty; + + if (cd == 1) { - rdpup_begin_update(); - dx = dstx - srcx; - dy = dsty - srcy; - if ((dy < 0) || ((dy == 0) && (dx < 0))) - { - for (j = 0; j < num_clips; j++) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); - } - } - else - { - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); - } - } - rdpup_reset_clip(); - rdpup_end_update(); + rdpup_begin_update(); + rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); + rdpup_end_update(); } - } - RegionUninit(&clip_reg); - return rv; + else if (cd == 2) + { + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips > 0) + { + rdpup_begin_update(); + dx = dstx - srcx; + dy = dsty - srcy; + + if ((dy < 0) || ((dy == 0) && (dx < 0))) + { + for (j = 0; j < num_clips; j++) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); + } + } + else + { + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); + } + } + + rdpup_reset_clip(); + rdpup_end_update(); + } + } + + RegionUninit(&clip_reg); + return rv; } /******************************************************************************/ static RegionPtr rdpCopyAreaWndToPixmap(WindowPtr pSrcWnd, - PixmapPtr pDstPixmap, rdpPixmapRec* pDstPriv, + PixmapPtr pDstPixmap, rdpPixmapRec *pDstPriv, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { - int cd; - int lsrcx; - int lsrcy; - int ldstx; - int ldsty; - int num_clips; - int dx; - int dy; - int j; - BoxRec box; - RegionPtr rv; - RegionRec clip_reg; + int cd; + int lsrcx; + int lsrcy; + int ldstx; + int ldsty; + int num_clips; + int dx; + int dy; + int j; + BoxRec box; + RegionPtr rv; + RegionRec clip_reg; - LLOGLN(10, ("rdpCopyAreaWndToPixmap:")); + LLOGLN(10, ("rdpCopyAreaWndToPixmap:")); - rv = rdpCopyAreaOrg(&(pSrcWnd->drawable), &(pDstPixmap->drawable), - pGC, srcx, srcy, w, h, dstx, dsty); - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, &(pDstPixmap->drawable), pGC); - lsrcx = pSrcWnd->drawable.x + srcx; - lsrcy = pSrcWnd->drawable.y + srcy; - ldstx = pDstPixmap->drawable.x + dstx; - ldsty = pDstPixmap->drawable.y + dsty; - if (cd == 1) - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - rdpup_begin_update(); - rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); - rdpup_end_update(); - rdpup_switch_os_surface(-1); - } - else if (cd == 2) - { - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) + rv = rdpCopyAreaOrg(&(pSrcWnd->drawable), &(pDstPixmap->drawable), + pGC, srcx, srcy, w, h, dstx, dsty); + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, &(pDstPixmap->drawable), pGC); + lsrcx = pSrcWnd->drawable.x + srcx; + lsrcy = pSrcWnd->drawable.y + srcy; + ldstx = pDstPixmap->drawable.x + dstx; + ldsty = pDstPixmap->drawable.y + dsty; + + if (cd == 1) { - rdpup_switch_os_surface(pDstPriv->rdpindex); - rdpup_begin_update(); - dx = dstx - srcx; - dy = dsty - srcy; - if ((dy < 0) || ((dy == 0) && (dx < 0))) - { - for (j = 0; j < num_clips; j++) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); - } - } - else - { - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); - } - } - rdpup_reset_clip(); - rdpup_end_update(); - rdpup_switch_os_surface(-1); + rdpup_switch_os_surface(pDstPriv->rdpindex); + rdpup_begin_update(); + rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); + rdpup_end_update(); + rdpup_switch_os_surface(-1); } - } - RegionUninit(&clip_reg); - return rv; + else if (cd == 2) + { + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips > 0) + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + rdpup_begin_update(); + dx = dstx - srcx; + dy = dsty - srcy; + + if ((dy < 0) || ((dy == 0) && (dx < 0))) + { + for (j = 0; j < num_clips; j++) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); + } + } + else + { + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_screen_blt(ldstx, ldsty, w, h, lsrcx, lsrcy); + } + } + + rdpup_reset_clip(); + rdpup_end_update(); + rdpup_switch_os_surface(-1); + } + } + + RegionUninit(&clip_reg); + return rv; } /******************************************************************************/ /* draw from an off screen pixmap to a visible window */ static RegionPtr -rdpCopyAreaPixmapToWnd(PixmapPtr pSrcPixmap, rdpPixmapRec* pSrcPriv, +rdpCopyAreaPixmapToWnd(PixmapPtr pSrcPixmap, rdpPixmapRec *pSrcPriv, WindowPtr pDstWnd, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { - int lsrcx; - int lsrcy; - int ldstx; - int ldsty; - int cd; - int j; - int num_clips; - RegionPtr rv; - RegionRec clip_reg; - BoxRec box; + int lsrcx; + int lsrcy; + int ldstx; + int ldsty; + int cd; + int j; + int num_clips; + RegionPtr rv; + RegionRec clip_reg; + BoxRec box; - LLOGLN(10, ("rdpCopyAreaPixmapToWnd:")); + LLOGLN(10, ("rdpCopyAreaPixmapToWnd:")); - rv = rdpCopyAreaOrg(&(pSrcPixmap->drawable), &(pDstWnd->drawable), - pGC, srcx, srcy, w, h, dstx, dsty); - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, &(pDstWnd->drawable), pGC); - ldstx = pDstWnd->drawable.x + dstx; - ldsty = pDstWnd->drawable.y + dsty; - lsrcx = pSrcPixmap->drawable.x + srcx; - lsrcy = pSrcPixmap->drawable.y + srcy; - if (cd == 1) - { - rdpup_begin_update(); - rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); - rdpup_end_update(); - } - else if (cd == 2) - { - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) + rv = rdpCopyAreaOrg(&(pSrcPixmap->drawable), &(pDstWnd->drawable), + pGC, srcx, srcy, w, h, dstx, dsty); + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, &(pDstWnd->drawable), pGC); + ldstx = pDstWnd->drawable.x + dstx; + ldsty = pDstWnd->drawable.y + dsty; + lsrcx = pSrcPixmap->drawable.x + srcx; + lsrcy = pSrcPixmap->drawable.y + srcy; + + if (cd == 1) { - rdpup_begin_update(); - LLOGLN(10, ("rdpCopyAreaPixmapToWnd: num_clips %d", num_clips)); - for (j = 0; j < num_clips; j++) - { - box = REGION_RECTS(&clip_reg)[j]; - LLOGLN(10, ("rdpCopyAreaPixmapToWnd: %d %d %d %d", box.x1, box.y1, box.x2, box.y2)); - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - LLOGLN(10, ("rdpCopyAreaPixmapToWnd: %d %d", w, h)); + rdpup_begin_update(); rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); - } - rdpup_reset_clip(); - rdpup_end_update(); + rdpup_end_update(); } - } - RegionUninit(&clip_reg); - return rv; + else if (cd == 2) + { + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips > 0) + { + rdpup_begin_update(); + LLOGLN(10, ("rdpCopyAreaPixmapToWnd: num_clips %d", num_clips)); + + for (j = 0; j < num_clips; j++) + { + box = REGION_RECTS(&clip_reg)[j]; + LLOGLN(10, ("rdpCopyAreaPixmapToWnd: %d %d %d %d", box.x1, box.y1, box.x2, box.y2)); + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + LLOGLN(10, ("rdpCopyAreaPixmapToWnd: %d %d", w, h)); + rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); + } + + rdpup_reset_clip(); + rdpup_end_update(); + } + } + + RegionUninit(&clip_reg); + return rv; } /******************************************************************************/ /* draw from an off screen pixmap to an off screen pixmap */ static RegionPtr -rdpCopyAreaPixmapToPixmap(PixmapPtr pSrcPixmap, rdpPixmapRec* pSrcPriv, - PixmapPtr pDstPixmap, rdpPixmapRec* pDstPriv, +rdpCopyAreaPixmapToPixmap(PixmapPtr pSrcPixmap, rdpPixmapRec *pSrcPriv, + PixmapPtr pDstPixmap, rdpPixmapRec *pDstPriv, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { - int lsrcx; - int lsrcy; - int ldstx; - int ldsty; - int cd; - int j; - int num_clips; - RegionPtr rv; - RegionRec clip_reg; - BoxRec box; + int lsrcx; + int lsrcy; + int ldstx; + int ldsty; + int cd; + int j; + int num_clips; + RegionPtr rv; + RegionRec clip_reg; + BoxRec box; - LLOGLN(10, ("rdpCopyAreaPixmapToPixmap:")); + LLOGLN(10, ("rdpCopyAreaPixmapToPixmap:")); - rv = rdpCopyAreaOrg(&(pSrcPixmap->drawable), &(pDstPixmap->drawable), - pGC, srcx, srcy, w, h, dstx, dsty); - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, &(pDstPixmap->drawable), pGC); - LLOGLN(10, ("rdpCopyAreaPixmapToPixmap: cd %d", cd)); - ldstx = pDstPixmap->drawable.x + dstx; - ldsty = pDstPixmap->drawable.y + dsty; - lsrcx = pSrcPixmap->drawable.x + srcx; - lsrcy = pSrcPixmap->drawable.y + srcy; - if (cd == 1) - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - rdpup_begin_update(); - rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); - LLOGLN(10, ("%d %d %d %d %d %d", ldstx, ldsty, w, h, lsrcx, lsrcy)); - rdpup_end_update(); - rdpup_switch_os_surface(-1); - } - else if (cd == 2) - { - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) + rv = rdpCopyAreaOrg(&(pSrcPixmap->drawable), &(pDstPixmap->drawable), + pGC, srcx, srcy, w, h, dstx, dsty); + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, &(pDstPixmap->drawable), pGC); + LLOGLN(10, ("rdpCopyAreaPixmapToPixmap: cd %d", cd)); + ldstx = pDstPixmap->drawable.x + dstx; + ldsty = pDstPixmap->drawable.y + dsty; + lsrcx = pSrcPixmap->drawable.x + srcx; + lsrcy = pSrcPixmap->drawable.y + srcy; + + if (cd == 1) { - rdpup_switch_os_surface(pDstPriv->rdpindex); - rdpup_begin_update(); - LLOGLN(10, ("rdpCopyAreaPixmapToPixmap: num_clips %d", num_clips)); - for (j = 0; j < num_clips; j++) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_switch_os_surface(pDstPriv->rdpindex); + rdpup_begin_update(); rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); LLOGLN(10, ("%d %d %d %d %d %d", ldstx, ldsty, w, h, lsrcx, lsrcy)); - } - rdpup_reset_clip(); - rdpup_end_update(); - rdpup_switch_os_surface(-1); + rdpup_end_update(); + rdpup_switch_os_surface(-1); } - } - RegionUninit(&clip_reg); - return rv; + else if (cd == 2) + { + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips > 0) + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + rdpup_begin_update(); + LLOGLN(10, ("rdpCopyAreaPixmapToPixmap: num_clips %d", num_clips)); + + for (j = 0; j < num_clips; j++) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_paint_rect_os(ldstx, ldsty, w, h, pSrcPriv->rdpindex, lsrcx, lsrcy); + LLOGLN(10, ("%d %d %d %d %d %d", ldstx, ldsty, w, h, lsrcx, lsrcy)); + } + + rdpup_reset_clip(); + rdpup_end_update(); + rdpup_switch_os_surface(-1); + } + } + + RegionUninit(&clip_reg); + return rv; } /******************************************************************************/ @@ -328,222 +348,243 @@ RegionPtr rdpCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { - RegionPtr rv; - RegionRec clip_reg; - RegionRec box_reg; - RegionRec reg1; - int num_clips; - int cd; - int j; - int can_do_screen_blt; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - struct image_data id; - BoxRec box; - BoxPtr pbox; - PixmapPtr pSrcPixmap; - PixmapPtr pDstPixmap; - rdpPixmapRec* pSrcPriv; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; - WindowPtr pDstWnd; - WindowPtr pSrcWnd; + RegionPtr rv; + RegionRec clip_reg; + RegionRec box_reg; + RegionRec reg1; + int num_clips; + int cd; + int j; + int can_do_screen_blt; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + struct image_data id; + BoxRec box; + BoxPtr pbox; + PixmapPtr pSrcPixmap; + PixmapPtr pDstPixmap; + rdpPixmapRec *pSrcPriv; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; + WindowPtr pDstWnd; + WindowPtr pSrcWnd; - LLOGLN(10, ("rdpCopyArea:")); + LLOGLN(10, ("rdpCopyArea:")); - if (pSrc->type == DRAWABLE_WINDOW) - { - pSrcWnd = (WindowPtr)pSrc; - if (pSrcWnd->viewable) + if (pSrc->type == DRAWABLE_WINDOW) { - if (pDst->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDst; - if (pDstWnd->viewable) + pSrcWnd = (WindowPtr)pSrc; + + if (pSrcWnd->viewable) { - can_do_screen_blt = pGC->alu == GXcopy; - if (can_do_screen_blt) - { - return rdpCopyAreaWndToWnd(pSrcWnd, pDstWnd, pGC, - srcx, srcy, w, h, dstx, dsty); - } + if (pDst->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDst; + + if (pDstWnd->viewable) + { + can_do_screen_blt = pGC->alu == GXcopy; + + if (can_do_screen_blt) + { + return rdpCopyAreaWndToWnd(pSrcWnd, pDstWnd, pGC, + srcx, srcy, w, h, dstx, dsty); + } + } + } + else if (pDst->type == DRAWABLE_PIXMAP) + { + pDstPixmap = (PixmapPtr)pDst; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + can_do_screen_blt = pGC->alu == GXcopy; + + if (can_do_screen_blt) + { + rdpup_check_dirty(pDstPixmap, pDstPriv); + return rdpCopyAreaWndToPixmap(pSrcWnd, pDstPixmap, pDstPriv, pGC, + srcx, srcy, w, h, dstx, dsty); + } + } + } } - } - else if (pDst->type == DRAWABLE_PIXMAP) - { + } + + if (pSrc->type == DRAWABLE_PIXMAP) + { + pSrcPixmap = (PixmapPtr)pSrc; + pSrcPriv = GETPIXPRIV(pSrcPixmap); + + if (XRDP_IS_OS(pSrcPriv)) + { + if (pDst->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDst; + + if (pDstWnd->viewable) + { + rdpup_check_dirty(pSrcPixmap, pSrcPriv); + return rdpCopyAreaPixmapToWnd(pSrcPixmap, pSrcPriv, pDstWnd, pGC, + srcx, srcy, w, h, dstx, dsty); + } + } + else if (pDst->type == DRAWABLE_PIXMAP) + { + pDstPixmap = (PixmapPtr)pDst; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + if (g_can_do_pix_to_pix) + { + rdpup_check_dirty(pSrcPixmap, pSrcPriv); + rdpup_check_dirty(pDstPixmap, pDstPriv); + return rdpCopyAreaPixmapToPixmap(pSrcPixmap, pSrcPriv, + pDstPixmap, pDstPriv, + pGC, srcx, srcy, w, h, + dstx, dsty); + } + } + } + } + } + + /* do original call */ + rv = rdpCopyAreaOrg(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDst->type == DRAWABLE_PIXMAP) + { pDstPixmap = (PixmapPtr)pDst; pDstPriv = GETPIXPRIV(pDstPixmap); + if (XRDP_IS_OS(pDstPriv)) { - can_do_screen_blt = pGC->alu == GXcopy; - if (can_do_screen_blt) - { - rdpup_check_dirty(pDstPixmap, pDstPriv); - return rdpCopyAreaWndToPixmap(pSrcWnd, pDstPixmap, pDstPriv, pGC, - srcx, srcy, w, h, dstx, dsty); - } + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpCopyArea: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - } } - } - if (pSrc->type == DRAWABLE_PIXMAP) - { - pSrcPixmap = (PixmapPtr)pSrc; - pSrcPriv = GETPIXPRIV(pSrcPixmap); - if (XRDP_IS_OS(pSrcPriv)) + else { - if (pDst->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDst; - if (pDstWnd->viewable) + if (pDst->type == DRAWABLE_WINDOW) { - rdpup_check_dirty(pSrcPixmap, pSrcPriv); - return rdpCopyAreaPixmapToWnd(pSrcPixmap, pSrcPriv, pDstWnd, pGC, - srcx, srcy, w, h, dstx, dsty); + pDstWnd = (WindowPtr)pDst; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } } - } - else if (pDst->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDst; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + } + + if (!post_process) + { + return rv; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDst, pGC); + + if (cd == 1) + { + if (dirty_type != 0) { - if (g_can_do_pix_to_pix) - { - rdpup_check_dirty(pSrcPixmap, pSrcPriv); - rdpup_check_dirty(pDstPixmap, pDstPriv); - return rdpCopyAreaPixmapToPixmap(pSrcPixmap, pSrcPriv, - pDstPixmap, pDstPriv, - pGC, srcx, srcy, w, h, - dstx, dsty); - } + box.x1 = pDst->x + dstx; + box.y1 = pDst->y + dsty; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, pDst->x + dstx, pDst->y + dsty, w, h); + rdpup_end_update(); } - } } - } - - /* do original call */ - rv = rdpCopyAreaOrg(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDst->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDst; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + else if (cd == 2) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpCopyArea: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } - } - } - else - { - if (pDst->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDst; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return rv; - } - - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDst, pGC); - if (cd == 1) - { - if (dirty_type != 0) - { - box.x1 = pDst->x + dstx; - box.y1 = pDst->y + dsty; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, pDst->x + dstx, pDst->y + dsty, w, h); - rdpup_end_update(); - } - } - else if (cd == 2) - { - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) - { - if (dirty_type != 0) - { - box.x1 = pDst->x + dstx; - box.y1 = pDst->y + dsty; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(&box_reg, &box, 0); - RegionIntersect(&clip_reg, &clip_reg, &box_reg); - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type); - RegionUninit(&box_reg); - } - else if (got_id) - { - rdpup_begin_update(); - box.x1 = pDst->x + dstx; - box.y1 = pDst->y + dsty; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(&box_reg, &box, 0); - RegionIntersect(&clip_reg, &clip_reg, &box_reg); num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips < 10) + + if (num_clips > 0) { - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); - } + if (dirty_type != 0) + { + box.x1 = pDst->x + dstx; + box.y1 = pDst->y + dsty; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(&box_reg, &box, 0); + RegionIntersect(&clip_reg, &clip_reg, &box_reg); + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type); + RegionUninit(&box_reg); + } + else if (got_id) + { + rdpup_begin_update(); + box.x1 = pDst->x + dstx; + box.y1 = pDst->y + dsty; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(&box_reg, &box, 0); + RegionIntersect(&clip_reg, &clip_reg, &box_reg); + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips < 10) + { + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + } + else + { + pbox = RegionExtents(&clip_reg); + rdpup_send_area(&id, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } + + RegionUninit(&box_reg); + rdpup_end_update(); + } } - else - { - pbox = RegionExtents(&clip_reg); - rdpup_send_area(&id, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - } - RegionUninit(&box_reg); - rdpup_end_update(); - } } - } - RegionUninit(&clip_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } - return rv; + + RegionUninit(&clip_reg); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + + return rv; } diff --git a/xorg/X11R7.6/rdp/rdpCopyPlane.c b/xorg/X11R7.6/rdp/rdpCopyPlane.c index 389dc6e1..aa0e2c29 100644 --- a/xorg/X11R7.6/rdp/rdpCopyPlane.c +++ b/xorg/X11R7.6/rdp/rdpCopyPlane.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -49,15 +49,15 @@ rdpCopyPlaneOrg(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty, unsigned long bitPlane) { - RegionPtr rv; - rdpGCPtr priv; - GCFuncs* oldFuncs; + RegionPtr rv; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - rv = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, - w, h, dstx, dsty, bitPlane); - GC_OP_EPILOGUE(pGC); - return rv; + GC_OP_PROLOGUE(pGC); + rv = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, + w, h, dstx, dsty, bitPlane); + GC_OP_EPILOGUE(pGC); + return rv; } /******************************************************************************/ @@ -66,151 +66,163 @@ rdpCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty, unsigned long bitPlane) { - RegionPtr rv; - RegionRec clip_reg; - RegionRec box_reg; - RegionRec reg1; - RegionRec reg2; - int cd; - int num_clips; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - BoxPtr pbox; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionPtr rv; + RegionRec clip_reg; + RegionRec box_reg; + RegionRec reg1; + RegionRec reg2; + int cd; + int num_clips; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + BoxPtr pbox; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpCopyPlane:")); + LLOGLN(10, ("rdpCopyPlane:")); - /* do original call */ - rv = rdpCopyPlaneOrg(pSrc, pDst, pGC, srcx, srcy, w, h, - dstx, dsty, bitPlane); + /* do original call */ + rv = rdpCopyPlaneOrg(pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, bitPlane); - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDst->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDst; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) - { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpCopyPlane: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } - } - } - else - { - if (pDst->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDst; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return rv; - } + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDst, pGC); - if (cd == 1) - { - if (dirty_type != 0) + if (pDst->type == DRAWABLE_PIXMAP) { - box.x1 = pDst->x + dstx; - box.y1 = pDst->y + dsty; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); + pDstPixmap = (PixmapPtr)pDst; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpCopyPlane: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } } - else if (got_id) + else { - rdpup_begin_update(); - rdpup_send_area(&id, pDst->x + dstx, pDst->y + dsty, w, h); - rdpup_end_update(); + if (pDst->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDst; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } } - } - else if (cd == 2) - { - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) + + if (!post_process) + { + return rv; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDst, pGC); + + if (cd == 1) + { + if (dirty_type != 0) + { + box.x1 = pDst->x + dstx; + box.y1 = pDst->y + dsty; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, pDst->x + dstx, pDst->y + dsty, w, h); + rdpup_end_update(); + } + } + else if (cd == 2) { - if (dirty_type != 0) - { - box.x1 = pDst->x + dstx; - box.y1 = pDst->y + dsty; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(®1, &box, 0); - RegionInit(®2, NullBox, 0); - RegionCopy(®2, &clip_reg); - RegionIntersect(®1, ®1, ®2); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - RegionUninit(®2); - } - else if (got_id) - { - rdpup_begin_update(); - box.x1 = pDst->x + dstx; - box.y1 = pDst->y + dsty; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(&box_reg, &box, 0); - RegionIntersect(&clip_reg, &clip_reg, &box_reg); num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips < 10) + + if (num_clips > 0) { - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } + if (dirty_type != 0) + { + box.x1 = pDst->x + dstx; + box.y1 = pDst->y + dsty; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(®1, &box, 0); + RegionInit(®2, NullBox, 0); + RegionCopy(®2, &clip_reg); + RegionIntersect(®1, ®1, ®2); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + RegionUninit(®2); + } + else if (got_id) + { + rdpup_begin_update(); + box.x1 = pDst->x + dstx; + box.y1 = pDst->y + dsty; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(&box_reg, &box, 0); + RegionIntersect(&clip_reg, &clip_reg, &box_reg); + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips < 10) + { + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + } + else + { + pbox = RegionExtents(&clip_reg); + rdpup_send_area(&id, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } + + RegionUninit(&box_reg); + rdpup_end_update(); + } } - else - { - pbox = RegionExtents(&clip_reg); - rdpup_send_area(&id, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - } - RegionUninit(&box_reg); - rdpup_end_update(); - } } - } - RegionUninit(&clip_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } - return rv; + + RegionUninit(&clip_reg); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + + return rv; } diff --git a/xorg/X11R7.6/rdp/rdpFillPolygon.c b/xorg/X11R7.6/rdp/rdpFillPolygon.c index bf71c094..d1ea89ea 100644 --- a/xorg/X11R7.6/rdp/rdpFillPolygon.c +++ b/xorg/X11R7.6/rdp/rdpFillPolygon.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -49,12 +49,12 @@ rdpFillPolygonOrg(DrawablePtr pDrawable, GCPtr pGC, int shape, int mode, int count, DDXPointPtr pPts) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->FillPolygon(pDrawable, pGC, shape, mode, count, pPts); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->FillPolygon(pDrawable, pGC, shape, mode, count, pPts); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ @@ -63,158 +63,176 @@ rdpFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, int mode, int count, DDXPointPtr pPts) { - RegionRec clip_reg; - RegionRec box_reg; - RegionRec reg1; - int num_clips; - int cd; - int maxx; - int maxy; - int minx; - int miny; - int i; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec clip_reg; + RegionRec box_reg; + RegionRec reg1; + int num_clips; + int cd; + int maxx; + int maxy; + int minx; + int miny; + int i; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpFillPolygon:")); + LLOGLN(10, ("rdpFillPolygon:")); - box.x1 = 0; - box.y1 = 0; - box.x2 = 0; - box.y2 = 0; - if (count > 0) - { - maxx = pPts[0].x; - maxy = pPts[0].y; - minx = maxx; - miny = maxy; - for (i = 1; i < count; i++) - { - if (pPts[i].x > maxx) - { - maxx = pPts[i].x; - } - if (pPts[i].x < minx) - { - minx = pPts[i].x; - } - if (pPts[i].y > maxy) - { - maxy = pPts[i].y; - } - if (pPts[i].y < miny) - { - miny = pPts[i].y; - } - } - box.x1 = pDrawable->x + minx; - box.y1 = pDrawable->y + miny; - box.x2 = pDrawable->x + maxx + 1; - box.y2 = pDrawable->y + maxy + 1; - } + box.x1 = 0; + box.y1 = 0; + box.x2 = 0; + box.y2 = 0; - /* do original call */ - rdpFillPolygonOrg(pDrawable, pGC, shape, mode, count, pPts); + if (count > 0) + { + maxx = pPts[0].x; + maxy = pPts[0].y; + minx = maxx; + miny = maxy; - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) - { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpFillPolygon: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } - } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return; - } - - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - if (cd == 1) - { - if (dirty_type != 0) - { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); - } - } - else if (cd == 2) - { - RegionInit(&box_reg, &box, 0); - RegionIntersect(&clip_reg, &clip_reg, &box_reg); - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + for (i = 1; i < count; i++) { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + if (pPts[i].x > maxx) + { + maxx = pPts[i].x; + } + + if (pPts[i].x < minx) + { + minx = pPts[i].x; + } + + if (pPts[i].y > maxy) + { + maxy = pPts[i].y; + } + + if (pPts[i].y < miny) + { + miny = pPts[i].y; + } } - rdpup_end_update(); - } + + box.x1 = pDrawable->x + minx; + box.y1 = pDrawable->y + miny; + box.x2 = pDrawable->x + maxx + 1; + box.y2 = pDrawable->y + maxy + 1; + } + + /* do original call */ + rdpFillPolygonOrg(pDrawable, pGC, shape, mode, count, pPts); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) + { + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpFillPolygon: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } + } + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + + if (cd == 1) + { + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + else if (cd == 2) + { + RegionInit(&box_reg, &box, 0); + RegionIntersect(&clip_reg, &clip_reg, &box_reg); + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(&box_reg); + } + + RegionUninit(&clip_reg); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); } - RegionUninit(&box_reg); - } - RegionUninit(&clip_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } } diff --git a/xorg/X11R7.6/rdp/rdpFillSpans.c b/xorg/X11R7.6/rdp/rdpFillSpans.c index 5c3dcc67..b647dabc 100644 --- a/xorg/X11R7.6/rdp/rdpFillSpans.c +++ b/xorg/X11R7.6/rdp/rdpFillSpans.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -45,70 +45,77 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ static void rdpFillSpansOrg(DrawablePtr pDrawable, GCPtr pGC, int nInit, - DDXPointPtr pptInit, int* pwidthInit, int fSorted) + DDXPointPtr pptInit, int *pwidthInit, int fSorted) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->FillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->FillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void rdpFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit, - DDXPointPtr pptInit, int* pwidthInit, int fSorted) + DDXPointPtr pptInit, int *pwidthInit, int fSorted) { - RegionRec clip_reg; - int cd; - int got_id; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; + RegionRec clip_reg; + int cd; + int got_id; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; - LLOGLN(10, ("rdpFillSpans: todo")); + LLOGLN(10, ("rdpFillSpans: todo")); - /* do original call */ - rdpFillSpansOrg(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); + /* do original call */ + rdpFillSpansOrg(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - rdpup_switch_os_surface(pDstPriv->rdpindex); - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) + else { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - rdpup_get_screen_image_rect(&id); - got_id = 1; - } + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } } - } - if (!got_id) - { - return; - } - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - if (cd == 1) - { - } - else if (cd == 2) - { - } - RegionUninit(&clip_reg); - rdpup_switch_os_surface(-1); + + if (!got_id) + { + return; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + + if (cd == 1) + { + } + else if (cd == 2) + { + } + + RegionUninit(&clip_reg); + rdpup_switch_os_surface(-1); } diff --git a/xorg/X11R7.6/rdp/rdpImageGlyphBlt.c b/xorg/X11R7.6/rdp/rdpImageGlyphBlt.c index 25d23a51..8de4af22 100644 --- a/xorg/X11R7.6/rdp/rdpImageGlyphBlt.c +++ b/xorg/X11R7.6/rdp/rdpImageGlyphBlt.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -47,146 +47,160 @@ extern int g_con_number; /* in rdpup.c */ void rdpImageGlyphBltOrg(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, - CharInfoPtr* ppci, pointer pglyphBase) + CharInfoPtr *ppci, pointer pglyphBase) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void rdpImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, - CharInfoPtr* ppci, pointer pglyphBase) + CharInfoPtr *ppci, pointer pglyphBase) { - RegionRec reg; - RegionRec reg1; - int num_clips; - int cd; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec reg; + RegionRec reg1; + int num_clips; + int cd; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpImageGlyphBlt:")); + LLOGLN(10, ("rdpImageGlyphBlt:")); - if (nglyph != 0) - { - GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); - } - - /* do original call */ - rdpImageGlyphBltOrg(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + if (nglyph != 0) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpImageGlyphBlt: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return; - } - RegionInit(®, NullBox, 0); - if (nglyph == 0) - { - cd = 0; - } - else - { - cd = rdp_get_clip(®, pDrawable, pGC); - } - if (cd == 1) - { - if (dirty_type != 0) + /* do original call */ + rdpImageGlyphBltOrg(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); - } - } - else if (cd == 2) - { - RegionInit(®1, &box, 0); - RegionIntersect(®, ®, ®1); - num_clips = REGION_NUM_RECTS(®); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(®)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpImageGlyphBlt: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - rdpup_end_update(); - } } - RegionUninit(®1); - } - RegionUninit(®); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } - return; + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return; + } + + RegionInit(®, NullBox, 0); + + if (nglyph == 0) + { + cd = 0; + } + else + { + cd = rdp_get_clip(®, pDrawable, pGC); + } + + if (cd == 1) + { + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + else if (cd == 2) + { + RegionInit(®1, &box, 0); + RegionIntersect(®, ®, ®1); + num_clips = REGION_NUM_RECTS(®); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(®1); + } + + RegionUninit(®); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + + return; } diff --git a/xorg/X11R7.6/rdp/rdpImageText16.c b/xorg/X11R7.6/rdp/rdpImageText16.c index 103344c6..0ba18564 100644 --- a/xorg/X11R7.6/rdp/rdpImageText16.c +++ b/xorg/X11R7.6/rdp/rdpImageText16.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -46,146 +46,160 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ void rdpImageText16Org(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, int count, unsigned short* chars) + int x, int y, int count, unsigned short *chars) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->ImageText16(pDrawable, pGC, x, y, count, chars); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->ImageText16(pDrawable, pGC, x, y, count, chars); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void rdpImageText16(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, int count, unsigned short* chars) + int x, int y, int count, unsigned short *chars) { - RegionRec reg; - RegionRec reg1; - int num_clips; - int cd; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec reg; + RegionRec reg1; + int num_clips; + int cd; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpImageText16:")); + LLOGLN(10, ("rdpImageText16:")); - if (count != 0) - { - GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); - } - - /* do original call */ - rdpImageText16Org(pDrawable, pGC, x, y, count, chars); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + if (count != 0) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpImageText16: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLY; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return; - } - RegionInit(®, NullBox, 0); - if (count == 0) - { - cd = 0; - } - else - { - cd = rdp_get_clip(®, pDrawable, pGC); - } - if (cd == 1) - { - if (dirty_type != 0) + /* do original call */ + rdpImageText16Org(pDrawable, pGC, x, y, count, chars); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); - } - } - else if (cd == 2) - { - RegionInit(®1, &box, 0); - RegionIntersect(®, ®, ®1); - num_clips = REGION_NUM_RECTS(®); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(®)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpImageText16: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLY; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - rdpup_end_update(); - } } - RegionUninit(®1); - } - RegionUninit(®); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } - return; + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return; + } + + RegionInit(®, NullBox, 0); + + if (count == 0) + { + cd = 0; + } + else + { + cd = rdp_get_clip(®, pDrawable, pGC); + } + + if (cd == 1) + { + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + else if (cd == 2) + { + RegionInit(®1, &box, 0); + RegionIntersect(®, ®, ®1); + num_clips = REGION_NUM_RECTS(®); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(®1); + } + + RegionUninit(®); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + + return; } diff --git a/xorg/X11R7.6/rdp/rdpImageText8.c b/xorg/X11R7.6/rdp/rdpImageText8.c index ba958a21..3d27731a 100644 --- a/xorg/X11R7.6/rdp/rdpImageText8.c +++ b/xorg/X11R7.6/rdp/rdpImageText8.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -46,146 +46,160 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ void rdpImageText8Org(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, int count, char* chars) + int x, int y, int count, char *chars) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->ImageText8(pDrawable, pGC, x, y, count, chars); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->ImageText8(pDrawable, pGC, x, y, count, chars); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void rdpImageText8(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, int count, char* chars) + int x, int y, int count, char *chars) { - RegionRec reg; - RegionRec reg1; - int num_clips; - int cd; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec reg; + RegionRec reg1; + int num_clips; + int cd; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpImageText8:")); + LLOGLN(10, ("rdpImageText8:")); - if (count != 0) - { - GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); - } - - /* do original call */ - rdpImageText8Org(pDrawable, pGC, x, y, count, chars); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + if (count != 0) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpImageText8: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return; - } - RegionInit(®, NullBox, 0); - if (count == 0) - { - cd = 0; - } - else - { - cd = rdp_get_clip(®, pDrawable, pGC); - } - if (cd == 1) - { - if (dirty_type != 0) + /* do original call */ + rdpImageText8Org(pDrawable, pGC, x, y, count, chars); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); - } - } - else if (cd == 2) - { - RegionInit(®1, &box, 0); - RegionIntersect(®, ®, ®1); - num_clips = REGION_NUM_RECTS(®); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(®)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpImageText8: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - rdpup_end_update(); - } } - RegionUninit(®1); - } - RegionUninit(®); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } - return; + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return; + } + + RegionInit(®, NullBox, 0); + + if (count == 0) + { + cd = 0; + } + else + { + cd = rdp_get_clip(®, pDrawable, pGC); + } + + if (cd == 1) + { + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + else if (cd == 2) + { + RegionInit(®1, &box, 0); + RegionIntersect(®, ®, ®1); + num_clips = REGION_NUM_RECTS(®); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(®1); + } + + RegionUninit(®); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + + return; } diff --git a/xorg/X11R7.6/rdp/rdpPolyArc.c b/xorg/X11R7.6/rdp/rdpPolyArc.c index ba890f0c..4b5212a6 100644 --- a/xorg/X11R7.6/rdp/rdpPolyArc.c +++ b/xorg/X11R7.6/rdp/rdpPolyArc.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -45,171 +45,191 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ void -rdpPolyArcOrg(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc* parcs) +rdpPolyArcOrg(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PolyArc(pDrawable, pGC, narcs, parcs); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PolyArc(pDrawable, pGC, narcs, parcs); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void -rdpPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc* parcs) +rdpPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) { - RegionRec clip_reg; - RegionPtr tmpRegion; - int cd; - int lw; - int extra; - int i; - int num_clips; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - xRectangle* rects; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec clip_reg; + RegionPtr tmpRegion; + int cd; + int lw; + int extra; + int i; + int num_clips; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + xRectangle *rects; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolyArc:")); + LLOGLN(10, ("rdpPolyArc:")); - rects = 0; - if (narcs > 0) - { - rects = (xRectangle*)g_malloc(narcs * sizeof(xRectangle), 0); - lw = pGC->lineWidth; - if (lw == 0) - { - lw = 1; - } - extra = lw / 2; - for (i = 0; i < narcs; i++) - { - rects[i].x = (parcs[i].x - extra) + pDrawable->x; - rects[i].y = (parcs[i].y - extra) + pDrawable->y; - rects[i].width = parcs[i].width + lw; - rects[i].height = parcs[i].height + lw; - } - } + rects = 0; - /* do original call */ - rdpPolyArcOrg(pDrawable, pGC, narcs, parcs); + if (narcs > 0) + { + rects = (xRectangle *)g_malloc(narcs * sizeof(xRectangle), 0); + lw = pGC->lineWidth; - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) - { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolyArc: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + if (lw == 0) + { + lw = 1; + } + + extra = lw / 2; + + for (i = 0; i < narcs; i++) + { + rects[i].x = (parcs[i].x - extra) + pDrawable->x; + rects[i].y = (parcs[i].y - extra) + pDrawable->y; + rects[i].width = parcs[i].width + lw; + rects[i].height = parcs[i].height + lw; + } } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) + + /* do original call */ + rdpPolyArcOrg(pDrawable, pGC, narcs, parcs); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolyArc: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } } - } - if (!post_process) - { + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + g_free(rects); + return; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + + if (cd == 1) + { + if (rects != 0) + { + tmpRegion = RegionFromRects(narcs, rects, CT_NONE); + num_clips = REGION_NUM_RECTS(tmpRegion); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (i = num_clips - 1; i >= 0; i--) + { + box = REGION_RECTS(tmpRegion)[i]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionDestroy(tmpRegion); + } + } + else if (cd == 2) + { + if (rects != 0) + { + tmpRegion = RegionFromRects(narcs, rects, CT_NONE); + RegionIntersect(tmpRegion, tmpRegion, &clip_reg); + num_clips = REGION_NUM_RECTS(tmpRegion); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (i = num_clips - 1; i >= 0; i--) + { + box = REGION_RECTS(tmpRegion)[i]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionDestroy(tmpRegion); + } + } + + RegionUninit(&clip_reg); g_free(rects); - return; - } - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - if (cd == 1) - { - if (rects != 0) + if (reset_surface) { - tmpRegion = RegionFromRects(narcs, rects, CT_NONE); - num_clips = REGION_NUM_RECTS(tmpRegion); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (i = num_clips - 1; i >= 0; i--) - { - box = REGION_RECTS(tmpRegion)[i]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); - } - rdpup_end_update(); - } - } - RegionDestroy(tmpRegion); + rdpup_switch_os_surface(-1); } - } - else if (cd == 2) - { - if (rects != 0) - { - tmpRegion = RegionFromRects(narcs, rects, CT_NONE); - RegionIntersect(tmpRegion, tmpRegion, &clip_reg); - num_clips = REGION_NUM_RECTS(tmpRegion); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (i = num_clips - 1; i >= 0; i--) - { - box = REGION_RECTS(tmpRegion)[i]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); - } - rdpup_end_update(); - } - } - RegionDestroy(tmpRegion); - } - } - RegionUninit(&clip_reg); - g_free(rects); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } } diff --git a/xorg/X11R7.6/rdp/rdpPolyFillArc.c b/xorg/X11R7.6/rdp/rdpPolyFillArc.c index cb8f2801..5fd568ad 100644 --- a/xorg/X11R7.6/rdp/rdpPolyFillArc.c +++ b/xorg/X11R7.6/rdp/rdpPolyFillArc.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -45,171 +45,191 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ void -rdpPolyFillArcOrg(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc* parcs) +rdpPolyFillArcOrg(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PolyFillArc(pDrawable, pGC, narcs, parcs); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PolyFillArc(pDrawable, pGC, narcs, parcs); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void -rdpPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc* parcs) +rdpPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs) { - RegionRec clip_reg; - RegionPtr tmpRegion; - int cd; - int lw; - int extra; - int i; - int num_clips; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - xRectangle* rects; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec clip_reg; + RegionPtr tmpRegion; + int cd; + int lw; + int extra; + int i; + int num_clips; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + xRectangle *rects; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolyFillArc:")); + LLOGLN(10, ("rdpPolyFillArc:")); - rects = 0; - if (narcs > 0) - { - rects = (xRectangle*)g_malloc(narcs * sizeof(xRectangle), 0); - lw = pGC->lineWidth; - if (lw == 0) - { - lw = 1; - } - extra = lw / 2; - for (i = 0; i < narcs; i++) - { - rects[i].x = (parcs[i].x - extra) + pDrawable->x; - rects[i].y = (parcs[i].y - extra) + pDrawable->y; - rects[i].width = parcs[i].width + lw; - rects[i].height = parcs[i].height + lw; - } - } + rects = 0; - /* do original call */ - rdpPolyFillArcOrg(pDrawable, pGC, narcs, parcs); + if (narcs > 0) + { + rects = (xRectangle *)g_malloc(narcs * sizeof(xRectangle), 0); + lw = pGC->lineWidth; - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) - { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolyFillArc: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLY; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + if (lw == 0) + { + lw = 1; + } + + extra = lw / 2; + + for (i = 0; i < narcs; i++) + { + rects[i].x = (parcs[i].x - extra) + pDrawable->x; + rects[i].y = (parcs[i].y - extra) + pDrawable->y; + rects[i].width = parcs[i].width + lw; + rects[i].height = parcs[i].height + lw; + } } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) + + /* do original call */ + rdpPolyFillArcOrg(pDrawable, pGC, narcs, parcs); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolyFillArc: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLY; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } } - } - if (!post_process) - { + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + g_free(rects); + return; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + + if (cd == 1) + { + if (rects != 0) + { + tmpRegion = RegionFromRects(narcs, rects, CT_NONE); + num_clips = REGION_NUM_RECTS(tmpRegion); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (i = num_clips - 1; i >= 0; i--) + { + box = REGION_RECTS(tmpRegion)[i]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionDestroy(tmpRegion); + } + } + else if (cd == 2) + { + if (rects != 0) + { + tmpRegion = RegionFromRects(narcs, rects, CT_NONE); + RegionIntersect(tmpRegion, tmpRegion, &clip_reg); + num_clips = REGION_NUM_RECTS(tmpRegion); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (i = num_clips - 1; i >= 0; i--) + { + box = REGION_RECTS(tmpRegion)[i]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionDestroy(tmpRegion); + } + } + + RegionUninit(&clip_reg); g_free(rects); - return; - } - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - if (cd == 1) - { - if (rects != 0) + if (reset_surface) { - tmpRegion = RegionFromRects(narcs, rects, CT_NONE); - num_clips = REGION_NUM_RECTS(tmpRegion); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (i = num_clips - 1; i >= 0; i--) - { - box = REGION_RECTS(tmpRegion)[i]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); - } - rdpup_end_update(); - } - } - RegionDestroy(tmpRegion); + rdpup_switch_os_surface(-1); } - } - else if (cd == 2) - { - if (rects != 0) - { - tmpRegion = RegionFromRects(narcs, rects, CT_NONE); - RegionIntersect(tmpRegion, tmpRegion, &clip_reg); - num_clips = REGION_NUM_RECTS(tmpRegion); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, tmpRegion, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (i = num_clips - 1; i >= 0; i--) - { - box = REGION_RECTS(tmpRegion)[i]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); - } - rdpup_end_update(); - } - } - RegionDestroy(tmpRegion); - } - } - RegionUninit(&clip_reg); - g_free(rects); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } } diff --git a/xorg/X11R7.6/rdp/rdpPolyFillRect.c b/xorg/X11R7.6/rdp/rdpPolyFillRect.c index 5dda6b7e..7a860623 100644 --- a/xorg/X11R7.6/rdp/rdpPolyFillRect.c +++ b/xorg/X11R7.6/rdp/rdpPolyFillRect.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -46,210 +46,228 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ static void rdpPolyFillRectOrg(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, - xRectangle* prectInit) + xRectangle *prectInit) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PolyFillRect(pDrawable, pGC, nrectFill, prectInit); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PolyFillRect(pDrawable, pGC, nrectFill, prectInit); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void rdpPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, - xRectangle* prectInit) + xRectangle *prectInit) { - int j; - int cd; - int num_clips; - RegionRec clip_reg; - RegionPtr fill_reg; - BoxRec box; + int j; + int cd; + int num_clips; + RegionRec clip_reg; + RegionPtr fill_reg; + BoxRec box; - int got_id; - int dirty_type; - int post_process; - int reset_surface; + int got_id; + int dirty_type; + int post_process; + int reset_surface; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolyFillRect:")); + LLOGLN(10, ("rdpPolyFillRect:")); - /* make a copy of rects */ - fill_reg = RegionFromRects(nrectFill, prectInit, CT_NONE); + /* make a copy of rects */ + fill_reg = RegionFromRects(nrectFill, prectInit, CT_NONE); - /* do original call */ - rdpPolyFillRectOrg(pDrawable, pGC, nrectFill, prectInit); + /* do original call */ + rdpPolyFillRectOrg(pDrawable, pGC, nrectFill, prectInit); - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - post_process = 1; - if (g_do_dirty_os) - { - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_FILL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + + if (g_do_dirty_os) + { + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_FILL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) + else { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } } - } - if (!post_process) - { + + if (!post_process) + { + RegionDestroy(fill_reg); + return; + } + + RegionTranslate(fill_reg, pDrawable->x, pDrawable->y); + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + + if (cd == 1) /* no clip */ + { + if (dirty_type != 0) + { + if (pGC->fillStyle == 0 && /* solid fill */ + (pGC->alu == GXclear || + pGC->alu == GXset || + pGC->alu == GXinvert || + pGC->alu == GXnoop || + pGC->alu == GXand || + pGC->alu == GXcopy /*|| + pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ + { + draw_item_add_fill_region(pDirtyPriv, fill_reg, pGC->fgPixel, + pGC->alu); + } + else + { + draw_item_add_img_region(pDirtyPriv, fill_reg, GXcopy, RDI_IMGLL); + } + } + else if (got_id) + { + rdpup_begin_update(); + + if (pGC->fillStyle == 0 && /* solid fill */ + (pGC->alu == GXclear || + pGC->alu == GXset || + pGC->alu == GXinvert || + pGC->alu == GXnoop || + pGC->alu == GXand || + pGC->alu == GXcopy /*|| + pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ + { + rdpup_set_fgcolor(pGC->fgPixel); + rdpup_set_opcode(pGC->alu); + + for (j = REGION_NUM_RECTS(fill_reg) - 1; j >= 0; j--) + { + box = REGION_RECTS(fill_reg)[j]; + rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_set_opcode(GXcopy); + } + else /* non solid fill */ + { + for (j = REGION_NUM_RECTS(fill_reg) - 1; j >= 0; j--) + { + box = REGION_RECTS(fill_reg)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + } + + rdpup_end_update(); + } + } + else if (cd == 2) /* clip */ + { + RegionIntersect(&clip_reg, &clip_reg, fill_reg); + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + if (pGC->fillStyle == 0 && /* solid fill */ + (pGC->alu == GXclear || + pGC->alu == GXset || + pGC->alu == GXinvert || + pGC->alu == GXnoop || + pGC->alu == GXand || + pGC->alu == GXcopy /*|| + pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ + { + draw_item_add_fill_region(pDirtyPriv, &clip_reg, pGC->fgPixel, + pGC->alu); + } + else + { + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, RDI_IMGLL); + } + } + else if (got_id) + { + rdpup_begin_update(); + + if (pGC->fillStyle == 0 && /* solid fill */ + (pGC->alu == GXclear || + pGC->alu == GXset || + pGC->alu == GXinvert || + pGC->alu == GXnoop || + pGC->alu == GXand || + pGC->alu == GXcopy /*|| + pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ + { + rdpup_set_fgcolor(pGC->fgPixel); + rdpup_set_opcode(pGC->alu); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_set_opcode(GXcopy); + } + else /* non solid fill */ + { + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + } + + rdpup_end_update(); + } + } + } + + RegionUninit(&clip_reg); RegionDestroy(fill_reg); - return; - } - RegionTranslate(fill_reg, pDrawable->x, pDrawable->y); - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - if (cd == 1) /* no clip */ - { - if (dirty_type != 0) + + if (reset_surface) { - if (pGC->fillStyle == 0 && /* solid fill */ - (pGC->alu == GXclear || - pGC->alu == GXset || - pGC->alu == GXinvert || - pGC->alu == GXnoop || - pGC->alu == GXand || - pGC->alu == GXcopy /*|| - pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ - { - draw_item_add_fill_region(pDirtyPriv, fill_reg, pGC->fgPixel, - pGC->alu); - } - else - { - draw_item_add_img_region(pDirtyPriv, fill_reg, GXcopy, RDI_IMGLL); - } + rdpup_switch_os_surface(-1); } - else if (got_id) - { - rdpup_begin_update(); - if (pGC->fillStyle == 0 && /* solid fill */ - (pGC->alu == GXclear || - pGC->alu == GXset || - pGC->alu == GXinvert || - pGC->alu == GXnoop || - pGC->alu == GXand || - pGC->alu == GXcopy /*|| - pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ - { - rdpup_set_fgcolor(pGC->fgPixel); - rdpup_set_opcode(pGC->alu); - for (j = REGION_NUM_RECTS(fill_reg) - 1; j >= 0; j--) - { - box = REGION_RECTS(fill_reg)[j]; - rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - rdpup_set_opcode(GXcopy); - } - else /* non solid fill */ - { - for (j = REGION_NUM_RECTS(fill_reg) - 1; j >= 0; j--) - { - box = REGION_RECTS(fill_reg)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); - } - } - rdpup_end_update(); - } - } - else if (cd == 2) /* clip */ - { - RegionIntersect(&clip_reg, &clip_reg, fill_reg); - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) - { - if (dirty_type != 0) - { - if (pGC->fillStyle == 0 && /* solid fill */ - (pGC->alu == GXclear || - pGC->alu == GXset || - pGC->alu == GXinvert || - pGC->alu == GXnoop || - pGC->alu == GXand || - pGC->alu == GXcopy /*|| - pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ - { - draw_item_add_fill_region(pDirtyPriv, &clip_reg, pGC->fgPixel, - pGC->alu); - } - else - { - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, RDI_IMGLL); - } - } - else if (got_id) - { - rdpup_begin_update(); - if (pGC->fillStyle == 0 && /* solid fill */ - (pGC->alu == GXclear || - pGC->alu == GXset || - pGC->alu == GXinvert || - pGC->alu == GXnoop || - pGC->alu == GXand || - pGC->alu == GXcopy /*|| - pGC->alu == GXxor*/)) /* todo, why dosen't xor work? */ - { - rdpup_set_fgcolor(pGC->fgPixel); - rdpup_set_opcode(pGC->alu); - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - rdpup_set_opcode(GXcopy); - } - else /* non solid fill */ - { - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - } - rdpup_end_update(); - } - } - } - RegionUninit(&clip_reg); - RegionDestroy(fill_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } } diff --git a/xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c b/xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c index 89ae85b4..62fc6e8e 100644 --- a/xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c +++ b/xorg/X11R7.6/rdp/rdpPolyGlyphBlt.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -47,147 +47,161 @@ extern int g_con_number; /* in rdpup.c */ void rdpPolyGlyphBltOrg(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, - CharInfoPtr* ppci, pointer pglyphBase) + CharInfoPtr *ppci, pointer pglyphBase) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void rdpPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, - CharInfoPtr* ppci, pointer pglyphBase) + CharInfoPtr *ppci, pointer pglyphBase) { - RegionRec reg; - RegionRec reg1; - int num_clips; - int cd; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec reg; + RegionRec reg1; + int num_clips; + int cd; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolyGlyphBlt:")); + LLOGLN(10, ("rdpPolyGlyphBlt:")); - if (nglyph != 0) - { - GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); - } - - /* do original call */ - rdpPolyGlyphBltOrg(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + if (nglyph != 0) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolyGlyphBlt: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLY; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + GetTextBoundingBox(pDrawable, pGC->font, x, y, nglyph, &box); } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return; - } - RegionInit(®, NullBox, 0); - if (nglyph == 0) - { - cd = 0; - } - else - { - cd = rdp_get_clip(®, pDrawable, pGC); - } - if (cd == 1) - { - if (dirty_type != 0) + /* do original call */ + rdpPolyGlyphBltOrg(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); - } - } - else if (cd == 2) - { - RegionInit(®1, &box, 0); - RegionIntersect(®, ®, ®1); - num_clips = REGION_NUM_RECTS(®); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(®)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolyGlyphBlt: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLY; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - rdpup_end_update(); - } } - RegionUninit(®1); - } - RegionUninit(®); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } - return; + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return; + } + + RegionInit(®, NullBox, 0); + + if (nglyph == 0) + { + cd = 0; + } + else + { + cd = rdp_get_clip(®, pDrawable, pGC); + } + + if (cd == 1) + { + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + else if (cd == 2) + { + RegionInit(®1, &box, 0); + RegionIntersect(®, ®, ®1); + num_clips = REGION_NUM_RECTS(®); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(®1); + } + + RegionUninit(®); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + + return; } diff --git a/xorg/X11R7.6/rdp/rdpPolyPoint.c b/xorg/X11R7.6/rdp/rdpPolyPoint.c index cbbc4a98..ff112782 100644 --- a/xorg/X11R7.6/rdp/rdpPolyPoint.c +++ b/xorg/X11R7.6/rdp/rdpPolyPoint.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -48,12 +48,12 @@ void rdpPolyPointOrg(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr in_pts) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, in_pts); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, in_pts); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ @@ -61,209 +61,234 @@ void rdpPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr in_pts) { - RegionRec clip_reg; - RegionRec reg1; - RegionRec reg2; - int num_clips; - int cd; - int x; - int y; - int i; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - BoxRec total_box; - DDXPointPtr pts; - DDXPointRec stack_pts[32]; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec clip_reg; + RegionRec reg1; + RegionRec reg2; + int num_clips; + int cd; + int x; + int y; + int i; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + BoxRec total_box; + DDXPointPtr pts; + DDXPointRec stack_pts[32]; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolyPoint:")); - LLOGLN(10, ("rdpPolyPoint: npt %d", npt)); + LLOGLN(10, ("rdpPolyPoint:")); + LLOGLN(10, ("rdpPolyPoint: npt %d", npt)); - if (npt > 32) - { - pts = (DDXPointPtr)g_malloc(sizeof(DDXPointRec) * npt, 0); - } - else - { - pts = stack_pts; - } - for (i = 0; i < npt; i++) - { - pts[i].x = pDrawable->x + in_pts[i].x; - pts[i].y = pDrawable->y + in_pts[i].y; - if (i == 0) + if (npt > 32) { - total_box.x1 = pts[0].x; - total_box.y1 = pts[0].y; - total_box.x2 = pts[0].x; - total_box.y2 = pts[0].y; + pts = (DDXPointPtr)g_malloc(sizeof(DDXPointRec) * npt, 0); } else { - if (pts[i].x < total_box.x1) - { - total_box.x1 = pts[i].x; - } - if (pts[i].y < total_box.y1) - { - total_box.y1 = pts[i].y; - } - if (pts[i].x > total_box.x2) - { - total_box.x2 = pts[i].x; - } - if (pts[i].y > total_box.y2) - { - total_box.y2 = pts[i].y; - } + pts = stack_pts; } - /* todo, use this total_box */ - } - /* do original call */ - rdpPolyPointOrg(pDrawable, pGC, mode, npt, in_pts); + for (i = 0; i < npt; i++) + { + pts[i].x = pDrawable->x + in_pts[i].x; + pts[i].y = pDrawable->y + in_pts[i].y; - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) - { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolyPoint: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } - } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return; - } + if (i == 0) + { + total_box.x1 = pts[0].x; + total_box.y1 = pts[0].y; + total_box.x2 = pts[0].x; + total_box.y2 = pts[0].y; + } + else + { + if (pts[i].x < total_box.x1) + { + total_box.x1 = pts[i].x; + } - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - if (cd == 1) - { - if (npt > 0) - { - if (dirty_type != 0) - { - RegionInit(®1, NullBox, 0); - for (i = 0; i < npt; i++) - { - box.x1 = pts[i].x; - box.y1 = pts[i].y; - box.x2 = box.x1 + 1; - box.y2 = box.y1 + 1; - RegionInit(®2, &box, 0); - RegionUnion(®1, ®1, ®2); - RegionUninit(®2); + if (pts[i].y < total_box.y1) + { + total_box.y1 = pts[i].y; + } + + if (pts[i].x > total_box.x2) + { + total_box.x2 = pts[i].x; + } + + if (pts[i].y > total_box.y2) + { + total_box.y2 = pts[i].y; + } } - draw_item_add_fill_region(pDirtyPriv, ®1, pGC->fgPixel, - pGC->alu); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_set_fgcolor(pGC->fgPixel); - for (i = 0; i < npt; i++) - { - x = pts[i].x; - y = pts[i].y; - rdpup_fill_rect(x, y, 1, 1); - } - rdpup_end_update(); - } + + /* todo, use this total_box */ } - } - else if (cd == 2) - { - num_clips = REGION_NUM_RECTS(&clip_reg); - if (npt > 0 && num_clips > 0) + + /* do original call */ + rdpPolyPointOrg(pDrawable, pGC, mode, npt, in_pts); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - if (dirty_type != 0) - { - RegionInit(®1, NullBox, 0); - for (i = 0; i < npt; i++) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box.x1 = pts[i].x; - box.y1 = pts[i].y; - box.x2 = box.x1 + 1; - box.y2 = box.y1 + 1; - RegionInit(®2, &box, 0); - RegionUnion(®1, ®1, ®2); - RegionUninit(®2); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolyPoint: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - RegionIntersect(®1, ®1, &clip_reg); - draw_item_add_fill_region(pDirtyPriv, ®1, pGC->fgPixel, - pGC->alu); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_set_fgcolor(pGC->fgPixel); - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - for (i = 0; i < npt; i++) - { - x = pts[i].x; - y = pts[i].y; - rdpup_fill_rect(x, y, 1, 1); - } - } - rdpup_reset_clip(); - rdpup_end_update(); - } } - } - RegionUninit(&clip_reg); - if (pts != stack_pts) - { - g_free(pts); - } - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + + if (cd == 1) + { + if (npt > 0) + { + if (dirty_type != 0) + { + RegionInit(®1, NullBox, 0); + + for (i = 0; i < npt; i++) + { + box.x1 = pts[i].x; + box.y1 = pts[i].y; + box.x2 = box.x1 + 1; + box.y2 = box.y1 + 1; + RegionInit(®2, &box, 0); + RegionUnion(®1, ®1, ®2); + RegionUninit(®2); + } + + draw_item_add_fill_region(pDirtyPriv, ®1, pGC->fgPixel, + pGC->alu); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_set_fgcolor(pGC->fgPixel); + + for (i = 0; i < npt; i++) + { + x = pts[i].x; + y = pts[i].y; + rdpup_fill_rect(x, y, 1, 1); + } + + rdpup_end_update(); + } + } + } + else if (cd == 2) + { + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (npt > 0 && num_clips > 0) + { + if (dirty_type != 0) + { + RegionInit(®1, NullBox, 0); + + for (i = 0; i < npt; i++) + { + box.x1 = pts[i].x; + box.y1 = pts[i].y; + box.x2 = box.x1 + 1; + box.y2 = box.y1 + 1; + RegionInit(®2, &box, 0); + RegionUnion(®1, ®1, ®2); + RegionUninit(®2); + } + + RegionIntersect(®1, ®1, &clip_reg); + draw_item_add_fill_region(pDirtyPriv, ®1, pGC->fgPixel, + pGC->alu); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_set_fgcolor(pGC->fgPixel); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + + for (i = 0; i < npt; i++) + { + x = pts[i].x; + y = pts[i].y; + rdpup_fill_rect(x, y, 1, 1); + } + } + + rdpup_reset_clip(); + rdpup_end_update(); + } + } + } + + RegionUninit(&clip_reg); + + if (pts != stack_pts) + { + g_free(pts); + } + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } } diff --git a/xorg/X11R7.6/rdp/rdpPolyRectangle.c b/xorg/X11R7.6/rdp/rdpPolyRectangle.c index e2b38394..9f8a32fb 100644 --- a/xorg/X11R7.6/rdp/rdpPolyRectangle.c +++ b/xorg/X11R7.6/rdp/rdpPolyRectangle.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -46,240 +46,265 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ static void rdpPolyRectangleOrg(DrawablePtr pDrawable, GCPtr pGC, int nrects, - xRectangle* rects) + xRectangle *rects) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PolyRectangle(pDrawable, pGC, nrects, rects); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PolyRectangle(pDrawable, pGC, nrects, rects); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ /* tested with pGC->lineWidth = 0, 1, 2, 4 and opcodes 3 and 6 */ void rdpPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, - xRectangle* rects) + xRectangle *rects) { - RegionRec clip_reg; - RegionPtr fill_reg; - int num_clips; - int cd; - int lw; - int i; - int j; - int up; - int down; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - xRectangle* regRects; - xRectangle* r; - xRectangle* rect1; - BoxRec box; - struct image_data id; + RegionRec clip_reg; + RegionPtr fill_reg; + int num_clips; + int cd; + int lw; + int i; + int j; + int up; + int down; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + xRectangle *regRects; + xRectangle *r; + xRectangle *rect1; + BoxRec box; + struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolyRectangle:")); + LLOGLN(10, ("rdpPolyRectangle:")); - /* make a copy of rects */ - rect1 = (xRectangle*)g_malloc(sizeof(xRectangle) * nrects, 0); - for (i = 0; i < nrects; i++) - { - rect1[i] = rects[i]; - } + /* make a copy of rects */ + rect1 = (xRectangle *)g_malloc(sizeof(xRectangle) * nrects, 0); - /* do original call */ - rdpPolyRectangleOrg(pDrawable, pGC, nrects, rects); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) - { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolyRectangle: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } - } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - g_free(rect1); - return; - } - - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - regRects = 0; - if ((cd != 0) && (nrects > 0)) - { - regRects = (xRectangle*)g_malloc(nrects * 4 * sizeof(xRectangle), 0); - lw = pGC->lineWidth; - if (lw < 1) - { - lw = 1; - } - up = lw / 2; - down = 1 + (lw - 1) / 2; for (i = 0; i < nrects; i++) { - r = regRects + i * 4; - r->x = (rect1[i].x + pDrawable->x) - up; - r->y = (rect1[i].y + pDrawable->y) - up; - r->width = rect1[i].width + up + down; - r->height = lw; - r++; - r->x = (rect1[i].x + pDrawable->x) - up; - r->y = (rect1[i].y + pDrawable->y) + down; - r->width = lw; - r->height = MAX(rect1[i].height - (up + down), 0); - r++; - r->x = ((rect1[i].x + rect1[i].width) + pDrawable->x) - up; - r->y = (rect1[i].y + pDrawable->y) + down; - r->width = lw; - r->height = MAX(rect1[i].height - (up + down), 0); - r++; - r->x = (rect1[i].x + pDrawable->x) - up; - r->y = ((rect1[i].y + rect1[i].height) + pDrawable->y) - up; - r->width = rect1[i].width + up + down; - r->height = lw; + rect1[i] = rects[i]; } - } - if (cd == 1) - { - if (regRects != 0) + + /* do original call */ + rdpPolyRectangleOrg(pDrawable, pGC, nrects, rects); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - if (dirty_type != 0) - { - fill_reg = RegionFromRects(nrects * 4, regRects, CT_NONE); - if (pGC->lineStyle == LineSolid) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - draw_item_add_fill_region(pDirtyPriv, fill_reg, pGC->fgPixel, - pGC->alu); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolyRectangle: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - else - { - draw_item_add_img_region(pDirtyPriv, fill_reg, GXcopy, dirty_type); - } - RegionDestroy(fill_reg); - } - else if (got_id) - { - rdpup_begin_update(); - if (pGC->lineStyle == LineSolid) - { - rdpup_set_fgcolor(pGC->fgPixel); - rdpup_set_opcode(pGC->alu); - for (i = 0; i < nrects * 4; i++) - { - r = regRects + i; - rdpup_fill_rect(r->x, r->y, r->width, r->height); - } - rdpup_set_opcode(GXcopy); - } - else - { - for (i = 0; i < nrects * 4; i++) - { - r = regRects + i; - rdpup_send_area(&id, r->x, r->y, r->width, r->height); - } - } - rdpup_end_update(); - } } - } - else if (cd == 2) - { - if (regRects != 0) + else { - fill_reg = RegionFromRects(nrects * 4, regRects, CT_NONE); - RegionIntersect(&clip_reg, &clip_reg, fill_reg); - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) - { - if (dirty_type != 0) + if (pDrawable->type == DRAWABLE_WINDOW) { - if (pGC->lineStyle == LineSolid) - { - draw_item_add_fill_region(pDirtyPriv, &clip_reg, pGC->fgPixel, - pGC->alu); - } - else - { - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type); - } - } - else if (got_id) - { - rdpup_begin_update(); - if (pGC->lineStyle == LineSolid) - { - rdpup_set_fgcolor(pGC->fgPixel); - rdpup_set_opcode(pGC->alu); - for (j = num_clips - 1; j >= 0; j--) + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; } - rdpup_set_opcode(GXcopy); - } - else - { - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - } - rdpup_end_update(); } - } - RegionDestroy(fill_reg); } - } - RegionUninit(&clip_reg); - g_free(regRects); - g_free(rect1); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } + + if (!post_process) + { + g_free(rect1); + return; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + regRects = 0; + + if ((cd != 0) && (nrects > 0)) + { + regRects = (xRectangle *)g_malloc(nrects * 4 * sizeof(xRectangle), 0); + lw = pGC->lineWidth; + + if (lw < 1) + { + lw = 1; + } + + up = lw / 2; + down = 1 + (lw - 1) / 2; + + for (i = 0; i < nrects; i++) + { + r = regRects + i * 4; + r->x = (rect1[i].x + pDrawable->x) - up; + r->y = (rect1[i].y + pDrawable->y) - up; + r->width = rect1[i].width + up + down; + r->height = lw; + r++; + r->x = (rect1[i].x + pDrawable->x) - up; + r->y = (rect1[i].y + pDrawable->y) + down; + r->width = lw; + r->height = MAX(rect1[i].height - (up + down), 0); + r++; + r->x = ((rect1[i].x + rect1[i].width) + pDrawable->x) - up; + r->y = (rect1[i].y + pDrawable->y) + down; + r->width = lw; + r->height = MAX(rect1[i].height - (up + down), 0); + r++; + r->x = (rect1[i].x + pDrawable->x) - up; + r->y = ((rect1[i].y + rect1[i].height) + pDrawable->y) - up; + r->width = rect1[i].width + up + down; + r->height = lw; + } + } + + if (cd == 1) + { + if (regRects != 0) + { + if (dirty_type != 0) + { + fill_reg = RegionFromRects(nrects * 4, regRects, CT_NONE); + + if (pGC->lineStyle == LineSolid) + { + draw_item_add_fill_region(pDirtyPriv, fill_reg, pGC->fgPixel, + pGC->alu); + } + else + { + draw_item_add_img_region(pDirtyPriv, fill_reg, GXcopy, dirty_type); + } + + RegionDestroy(fill_reg); + } + else if (got_id) + { + rdpup_begin_update(); + + if (pGC->lineStyle == LineSolid) + { + rdpup_set_fgcolor(pGC->fgPixel); + rdpup_set_opcode(pGC->alu); + + for (i = 0; i < nrects * 4; i++) + { + r = regRects + i; + rdpup_fill_rect(r->x, r->y, r->width, r->height); + } + + rdpup_set_opcode(GXcopy); + } + else + { + for (i = 0; i < nrects * 4; i++) + { + r = regRects + i; + rdpup_send_area(&id, r->x, r->y, r->width, r->height); + } + } + + rdpup_end_update(); + } + } + } + else if (cd == 2) + { + if (regRects != 0) + { + fill_reg = RegionFromRects(nrects * 4, regRects, CT_NONE); + RegionIntersect(&clip_reg, &clip_reg, fill_reg); + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + if (pGC->lineStyle == LineSolid) + { + draw_item_add_fill_region(pDirtyPriv, &clip_reg, pGC->fgPixel, + pGC->alu); + } + else + { + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type); + } + } + else if (got_id) + { + rdpup_begin_update(); + + if (pGC->lineStyle == LineSolid) + { + rdpup_set_fgcolor(pGC->fgPixel); + rdpup_set_opcode(pGC->alu); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_set_opcode(GXcopy); + } + else + { + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + } + + rdpup_end_update(); + } + } + + RegionDestroy(fill_reg); + } + } + + RegionUninit(&clip_reg); + g_free(regRects); + g_free(rect1); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } } diff --git a/xorg/X11R7.6/rdp/rdpPolySegment.c b/xorg/X11R7.6/rdp/rdpPolySegment.c index efab3cc0..c748c892 100644 --- a/xorg/X11R7.6/rdp/rdpPolySegment.c +++ b/xorg/X11R7.6/rdp/rdpPolySegment.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -45,168 +45,183 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ void -rdpPolySegmentOrg(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment* pSegs) +rdpPolySegmentOrg(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *pSegs) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PolySegment(pDrawable, pGC, nseg, pSegs); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PolySegment(pDrawable, pGC, nseg, pSegs); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void -rdpPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment* pSegs) +rdpPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *pSegs) { - RegionRec clip_reg; - int cd; - int i; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - xSegment* segs; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec clip_reg; + int cd; + int i; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + xSegment *segs; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolySegment:")); - LLOGLN(10, (" nseg %d", nseg)); + LLOGLN(10, ("rdpPolySegment:")); + LLOGLN(10, (" nseg %d", nseg)); - segs = 0; - if (nseg) /* get the rects */ - { - segs = (xSegment*)g_malloc(nseg * sizeof(xSegment), 0); - for (i = 0; i < nseg; i++) + segs = 0; + + if (nseg) /* get the rects */ { - segs[i].x1 = pSegs[i].x1 + pDrawable->x; - segs[i].y1 = pSegs[i].y1 + pDrawable->y; - segs[i].x2 = pSegs[i].x2 + pDrawable->x; - segs[i].y2 = pSegs[i].y2 + pDrawable->y; - } - } + segs = (xSegment *)g_malloc(nseg * sizeof(xSegment), 0); - /* do original call */ - rdpPolySegmentOrg(pDrawable, pGC, nseg, pSegs); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) - { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolySegment: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } - } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - g_free(segs); - return; - } - - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - LLOGLN(10, ("rdpPolySegment: cd %d", cd)); - if (cd == 1) /* no clip */ - { - if (segs != 0) - { - if (dirty_type != 0) - { - RegionUninit(&clip_reg); - RegionInit(&clip_reg, NullBox, 0); - RegionAroundSegs(&clip_reg, segs, nseg); - draw_item_add_line_region(pDirtyPriv, &clip_reg, pGC->fgPixel, - pGC->alu, pGC->lineWidth, segs, nseg, 1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_set_fgcolor(pGC->fgPixel); - rdpup_set_opcode(pGC->alu); - rdpup_set_pen(0, pGC->lineWidth); for (i = 0; i < nseg; i++) { - rdpup_draw_line(segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); + segs[i].x1 = pSegs[i].x1 + pDrawable->x; + segs[i].y1 = pSegs[i].y1 + pDrawable->y; + segs[i].x2 = pSegs[i].x2 + pDrawable->x; + segs[i].y2 = pSegs[i].y2 + pDrawable->y; } - rdpup_set_opcode(GXcopy); - rdpup_end_update(); - } } - } - else if (cd == 2) /* clip */ - { - if (segs != 0) + + /* do original call */ + rdpPolySegmentOrg(pDrawable, pGC, nseg, pSegs); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - if (dirty_type != 0) - { - draw_item_add_line_region(pDirtyPriv, &clip_reg, pGC->fgPixel, - pGC->alu, pGC->lineWidth, segs, nseg, 1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_set_fgcolor(pGC->fgPixel); - rdpup_set_opcode(pGC->alu); - rdpup_set_pen(0, pGC->lineWidth); - for (j = REGION_NUM_RECTS(&clip_reg) - 1; j >= 0; j--) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - for (i = 0; i < nseg; i++) - { - rdpup_draw_line(segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); - LLOGLN(10, (" %d %d %d %d", segs[i].x1, segs[i].y1, - segs[i].x2, segs[i].y2)); - } + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolySegment: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - rdpup_reset_clip(); - rdpup_set_opcode(GXcopy); - rdpup_end_update(); - } } - } - g_free(segs); - RegionUninit(&clip_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + g_free(segs); + return; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + LLOGLN(10, ("rdpPolySegment: cd %d", cd)); + + if (cd == 1) /* no clip */ + { + if (segs != 0) + { + if (dirty_type != 0) + { + RegionUninit(&clip_reg); + RegionInit(&clip_reg, NullBox, 0); + RegionAroundSegs(&clip_reg, segs, nseg); + draw_item_add_line_region(pDirtyPriv, &clip_reg, pGC->fgPixel, + pGC->alu, pGC->lineWidth, segs, nseg, 1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_set_fgcolor(pGC->fgPixel); + rdpup_set_opcode(pGC->alu); + rdpup_set_pen(0, pGC->lineWidth); + + for (i = 0; i < nseg; i++) + { + rdpup_draw_line(segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); + } + + rdpup_set_opcode(GXcopy); + rdpup_end_update(); + } + } + } + else if (cd == 2) /* clip */ + { + if (segs != 0) + { + if (dirty_type != 0) + { + draw_item_add_line_region(pDirtyPriv, &clip_reg, pGC->fgPixel, + pGC->alu, pGC->lineWidth, segs, nseg, 1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_set_fgcolor(pGC->fgPixel); + rdpup_set_opcode(pGC->alu); + rdpup_set_pen(0, pGC->lineWidth); + + for (j = REGION_NUM_RECTS(&clip_reg) - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + + for (i = 0; i < nseg; i++) + { + rdpup_draw_line(segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); + LLOGLN(10, (" %d %d %d %d", segs[i].x1, segs[i].y1, + segs[i].x2, segs[i].y2)); + } + } + + rdpup_reset_clip(); + rdpup_set_opcode(GXcopy); + rdpup_end_update(); + } + } + } + + g_free(segs); + RegionUninit(&clip_reg); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } } diff --git a/xorg/X11R7.6/rdp/rdpPolyText16.c b/xorg/X11R7.6/rdp/rdpPolyText16.c index aaea2434..34f8aa82 100644 --- a/xorg/X11R7.6/rdp/rdpPolyText16.c +++ b/xorg/X11R7.6/rdp/rdpPolyText16.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -46,148 +46,162 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ int rdpPolyText16Org(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, int count, unsigned short* chars) + int x, int y, int count, unsigned short *chars) { - int rv; - rdpGCPtr priv; - GCFuncs* oldFuncs; + int rv; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - rv = pGC->ops->PolyText16(pDrawable, pGC, x, y, count, chars); - GC_OP_EPILOGUE(pGC); - return rv; + GC_OP_PROLOGUE(pGC); + rv = pGC->ops->PolyText16(pDrawable, pGC, x, y, count, chars); + GC_OP_EPILOGUE(pGC); + return rv; } /******************************************************************************/ int rdpPolyText16(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, int count, unsigned short* chars) + int x, int y, int count, unsigned short *chars) { - RegionRec reg; - RegionRec reg1; - int num_clips; - int cd; - int j; - int rv; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec reg; + RegionRec reg1; + int num_clips; + int cd; + int j; + int rv; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolyText16:")); + LLOGLN(10, ("rdpPolyText16:")); - if (count != 0) - { - GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); - } - - /* do original call */ - rv = rdpPolyText16Org(pDrawable, pGC, x, y, count, chars); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + if (count != 0) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolyText16: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLY; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return rv; - } - RegionInit(®, NullBox, 0); - if (count == 0) - { - cd = 0; - } - else - { - cd = rdp_get_clip(®, pDrawable, pGC); - } - if (cd == 1) - { - if (dirty_type != 0) + /* do original call */ + rv = rdpPolyText16Org(pDrawable, pGC, x, y, count, chars); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); - } - } - else if (cd == 2) - { - RegionInit(®1, &box, 0); - RegionIntersect(®, ®, ®1); - num_clips = REGION_NUM_RECTS(®); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(®)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolyText16: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLY; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - rdpup_end_update(); - } } - RegionUninit(®1); - } - RegionUninit(®); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } - return rv; + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return rv; + } + + RegionInit(®, NullBox, 0); + + if (count == 0) + { + cd = 0; + } + else + { + cd = rdp_get_clip(®, pDrawable, pGC); + } + + if (cd == 1) + { + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + else if (cd == 2) + { + RegionInit(®1, &box, 0); + RegionIntersect(®, ®, ®1); + num_clips = REGION_NUM_RECTS(®); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(®1); + } + + RegionUninit(®); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + + return rv; } diff --git a/xorg/X11R7.6/rdp/rdpPolyText8.c b/xorg/X11R7.6/rdp/rdpPolyText8.c index 0b16cf26..39245ce1 100644 --- a/xorg/X11R7.6/rdp/rdpPolyText8.c +++ b/xorg/X11R7.6/rdp/rdpPolyText8.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -46,148 +46,162 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ int rdpPolyText8Org(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, int count, char* chars) + int x, int y, int count, char *chars) { - int rv; - rdpGCPtr priv; - GCFuncs* oldFuncs; + int rv; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - rv = pGC->ops->PolyText8(pDrawable, pGC, x, y, count, chars); - GC_OP_EPILOGUE(pGC); - return rv; + GC_OP_PROLOGUE(pGC); + rv = pGC->ops->PolyText8(pDrawable, pGC, x, y, count, chars); + GC_OP_EPILOGUE(pGC); + return rv; } /******************************************************************************/ int rdpPolyText8(DrawablePtr pDrawable, GCPtr pGC, - int x, int y, int count, char* chars) + int x, int y, int count, char *chars) { - RegionRec reg; - RegionRec reg1; - int num_clips; - int cd; - int j; - int rv; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec reg; + RegionRec reg1; + int num_clips; + int cd; + int j; + int rv; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolyText8:")); + LLOGLN(10, ("rdpPolyText8:")); - if (count != 0) - { - GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); - } - - /* do original call */ - rv = rdpPolyText8Org(pDrawable, pGC, x, y, count, chars); - - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + if (count != 0) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolyText8: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLY; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + GetTextBoundingBox(pDrawable, pGC->font, x, y, count, &box); } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return rv; - } - RegionInit(®, NullBox, 0); - if (count == 0) - { - cd = 0; - } - else - { - cd = rdp_get_clip(®, pDrawable, pGC); - } - if (cd == 1) - { - if (dirty_type != 0) + /* do original call */ + rv = rdpPolyText8Org(pDrawable, pGC, x, y, count, chars); + + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); - } - } - else if (cd == 2) - { - RegionInit(®1, &box, 0); - RegionIntersect(®, ®, ®1); - num_clips = REGION_NUM_RECTS(®); - if (num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); - } - else if (got_id) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(®)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolyText8: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLY; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - rdpup_end_update(); - } } - RegionUninit(®1); - } - RegionUninit(®); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } - return rv; + else + { + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return rv; + } + + RegionInit(®, NullBox, 0); + + if (count == 0) + { + cd = 0; + } + else + { + cd = rdp_get_clip(®, pDrawable, pGC); + } + + if (cd == 1) + { + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + else if (cd == 2) + { + RegionInit(®1, &box, 0); + RegionIntersect(®, ®, ®1); + num_clips = REGION_NUM_RECTS(®); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, ®, GXcopy, dirty_type); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(®1); + } + + RegionUninit(®); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } + + return rv; } diff --git a/xorg/X11R7.6/rdp/rdpPolylines.c b/xorg/X11R7.6/rdp/rdpPolylines.c index cbaf9c3e..d5208e42 100644 --- a/xorg/X11R7.6/rdp/rdpPolylines.c +++ b/xorg/X11R7.6/rdp/rdpPolylines.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -48,12 +48,12 @@ static void rdpPolylinesOrg(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr pptInit) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->Polylines(pDrawable, pGC, mode, npt, pptInit); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->Polylines(pDrawable, pGC, mode, npt, pptInit); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ @@ -61,194 +61,217 @@ void rdpPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr pptInit) { - RegionRec clip_reg; - int num_clips; - int cd; - int i; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - xSegment* segs; - int nseg; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec clip_reg; + int num_clips; + int cd; + int i; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + xSegment *segs; + int nseg; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPolylines:")); - LLOGLN(10, (" npt %d mode %d x %d y %d", npt, mode, - pDrawable->x, pDrawable->y)); + LLOGLN(10, ("rdpPolylines:")); + LLOGLN(10, (" npt %d mode %d x %d y %d", npt, mode, + pDrawable->x, pDrawable->y)); #if 0 - LLOGLN(0, (" points")); - for (i = 0; i < npt; i++) - { - LLOGLN(0, (" %d %d", pptInit[i].x, pptInit[i].y)); - } -#endif - /* convert lines to line segments */ - nseg = npt - 1; - segs = 0; - if (npt > 1) - { - segs = (xSegment*)g_malloc(sizeof(xSegment) * nseg, 0); - segs[0].x1 = pptInit[0].x + pDrawable->x; - segs[0].y1 = pptInit[0].y + pDrawable->y; - if (mode == CoordModeOrigin) + LLOGLN(0, (" points")); + + for (i = 0; i < npt; i++) { - segs[0].x2 = pptInit[1].x + pDrawable->x; - segs[0].y2 = pptInit[1].y + pDrawable->y; - for (i = 2; i < npt; i++) - { - segs[i - 1].x1 = segs[i - 2].x2; - segs[i - 1].y1 = segs[i - 2].y2; - segs[i - 1].x2 = pptInit[i].x + pDrawable->x; - segs[i - 1].y2 = pptInit[i].y + pDrawable->y; - } + LLOGLN(0, (" %d %d", pptInit[i].x, pptInit[i].y)); + } + +#endif + /* convert lines to line segments */ + nseg = npt - 1; + segs = 0; + + if (npt > 1) + { + segs = (xSegment *)g_malloc(sizeof(xSegment) * nseg, 0); + segs[0].x1 = pptInit[0].x + pDrawable->x; + segs[0].y1 = pptInit[0].y + pDrawable->y; + + if (mode == CoordModeOrigin) + { + segs[0].x2 = pptInit[1].x + pDrawable->x; + segs[0].y2 = pptInit[1].y + pDrawable->y; + + for (i = 2; i < npt; i++) + { + segs[i - 1].x1 = segs[i - 2].x2; + segs[i - 1].y1 = segs[i - 2].y2; + segs[i - 1].x2 = pptInit[i].x + pDrawable->x; + segs[i - 1].y2 = pptInit[i].y + pDrawable->y; + } + } + else + { + segs[0].x2 = segs[0].x1 + pptInit[1].x; + segs[0].y2 = segs[0].y1 + pptInit[1].y; + + for (i = 2; i < npt; i++) + { + segs[i - 1].x1 = segs[i - 2].x2; + segs[i - 1].y1 = segs[i - 2].y2; + segs[i - 1].x2 = segs[i - 1].x1 + pptInit[i].x; + segs[i - 1].y2 = segs[i - 1].y1 + pptInit[i].y; + } + } } else { - segs[0].x2 = segs[0].x1 + pptInit[1].x; - segs[0].y2 = segs[0].y1 + pptInit[1].y; - for (i = 2; i < npt; i++) - { - segs[i - 1].x1 = segs[i - 2].x2; - segs[i - 1].y1 = segs[i - 2].y2; - segs[i - 1].x2 = segs[i - 1].x1 + pptInit[i].x; - segs[i - 1].y2 = segs[i - 1].y1 + pptInit[i].y; - } + LLOGLN(0, ("rdpPolylines: weird npt [%d]", npt)); } - } - else - { - LLOGLN(0, ("rdpPolylines: weird npt [%d]", npt)); - } + #if 0 - LLOGLN(0, (" segments")); - for (i = 0; i < nseg; i++) - { - LLOGLN(0, (" %d %d %d %d", segs[i].x1, segs[i].y1, - segs[i].x2, segs[i].y2)); - } + LLOGLN(0, (" segments")); + + for (i = 0; i < nseg; i++) + { + LLOGLN(0, (" %d %d %d %d", segs[i].x1, segs[i].y1, + segs[i].x2, segs[i].y2)); + } + #endif - /* do original call */ - rdpPolylinesOrg(pDrawable, pGC, mode, npt, pptInit); + /* do original call */ + rdpPolylinesOrg(pDrawable, pGC, mode, npt, pptInit); - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPolylines: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLL; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPolylines: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLL; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) + else { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } } - } - if (!post_process) - { + + if (!post_process) + { + g_free(segs); + return; + } + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + + if (cd == 1) + { + if (segs != 0) + { + if (dirty_type != 0) + { + RegionUninit(&clip_reg); + RegionInit(&clip_reg, NullBox, 0); + RegionAroundSegs(&clip_reg, segs, nseg); + draw_item_add_line_region(pDirtyPriv, &clip_reg, pGC->fgPixel, + pGC->alu, pGC->lineWidth, segs, nseg, 0); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_set_fgcolor(pGC->fgPixel); + rdpup_set_opcode(pGC->alu); + rdpup_set_pen(0, pGC->lineWidth); + + for (i = 0; i < nseg; i++) + { + rdpup_draw_line(segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); + } + + rdpup_set_opcode(GXcopy); + rdpup_end_update(); + } + } + } + else if (cd == 2) + { + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (nseg != 0 && num_clips > 0) + { + if (dirty_type != 0) + { + draw_item_add_line_region(pDirtyPriv, &clip_reg, pGC->fgPixel, + pGC->alu, pGC->lineWidth, segs, nseg, 0); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_set_fgcolor(pGC->fgPixel); + rdpup_set_opcode(pGC->alu); + rdpup_set_pen(0, pGC->lineWidth); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + + for (i = 0; i < nseg; i++) + { + rdpup_draw_line(segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); + } + } + + rdpup_reset_clip(); + rdpup_set_opcode(GXcopy); + rdpup_end_update(); + } + } + } + g_free(segs); - return; - } + RegionUninit(&clip_reg); - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - if (cd == 1) - { - if (segs != 0) + if (reset_surface) { - if (dirty_type != 0) - { - RegionUninit(&clip_reg); - RegionInit(&clip_reg, NullBox, 0); - RegionAroundSegs(&clip_reg, segs, nseg); - draw_item_add_line_region(pDirtyPriv, &clip_reg, pGC->fgPixel, - pGC->alu, pGC->lineWidth, segs, nseg, 0); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_set_fgcolor(pGC->fgPixel); - rdpup_set_opcode(pGC->alu); - rdpup_set_pen(0, pGC->lineWidth); - for (i = 0; i < nseg; i++) - { - rdpup_draw_line(segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); - } - rdpup_set_opcode(GXcopy); - rdpup_end_update(); - } + rdpup_switch_os_surface(-1); } - } - else if (cd == 2) - { - num_clips = REGION_NUM_RECTS(&clip_reg); - if (nseg != 0 && num_clips > 0) - { - if (dirty_type != 0) - { - draw_item_add_line_region(pDirtyPriv, &clip_reg, pGC->fgPixel, - pGC->alu, pGC->lineWidth, segs, nseg, 0); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_set_fgcolor(pGC->fgPixel); - rdpup_set_opcode(pGC->alu); - rdpup_set_pen(0, pGC->lineWidth); - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - for (i = 0; i < nseg; i++) - { - rdpup_draw_line(segs[i].x1, segs[i].y1, segs[i].x2, segs[i].y2); - } - } - rdpup_reset_clip(); - rdpup_set_opcode(GXcopy); - rdpup_end_update(); - } - } - } - g_free(segs); - RegionUninit(&clip_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } } diff --git a/xorg/X11R7.6/rdp/rdpPushPixels.c b/xorg/X11R7.6/rdp/rdpPushPixels.c index 06c5ba9f..d990d6cb 100644 --- a/xorg/X11R7.6/rdp/rdpPushPixels.c +++ b/xorg/X11R7.6/rdp/rdpPushPixels.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -48,12 +48,12 @@ void rdpPushPixelsOrg(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, int w, int h, int x, int y) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PushPixels(pGC, pBitMap, pDst, w, h, x, y); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PushPixels(pGC, pBitMap, pDst, w, h, x, y); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ @@ -61,129 +61,141 @@ void rdpPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, int w, int h, int x, int y) { - RegionRec clip_reg; - RegionRec box_reg; - RegionRec reg1; - int num_clips; - int cd; - int j; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - BoxRec box; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec clip_reg; + RegionRec box_reg; + RegionRec reg1; + int num_clips; + int cd; + int j; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + BoxRec box; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpPushPixels:")); + LLOGLN(10, ("rdpPushPixels:")); - /* do original call */ - rdpPushPixelsOrg(pGC, pBitMap, pDst, w, h, x, y); + /* do original call */ + rdpPushPixelsOrg(pGC, pBitMap, pDst, w, h, x, y); - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDst->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDst; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) - { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPutImage: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLY; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } - } - } - else - { - if (pDst->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)pDst; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } - } - } - if (!post_process) - { - return; - } + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; - memset(&box, 0, sizeof(box)); - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDst, pGC); - if (cd == 1) - { - if (dirty_type != 0) + if (pDst->type == DRAWABLE_PIXMAP) { - box.x1 = pDst->x + x; - box.y1 = pDst->y + y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - rdpup_send_area(0, pDst->x + x, pDst->y + y, w, h); - rdpup_end_update(); - } - } - else if (cd == 2) - { - box.x1 = pDst->x + x; - box.y1 = pDst->y + y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(&box_reg, &box, 0); - RegionIntersect(&clip_reg, &clip_reg, &box_reg); - num_clips = REGION_NUM_RECTS(&clip_reg); - if (num_clips > 0) - { - if (dirty_type != 0) - { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type); - RegionUninit(®1); - } - else if (got_id) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + pDstPixmap = (PixmapPtr)pDst; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_send_area(0, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPutImage: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLY; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } } - rdpup_end_update(); - } } - RegionUninit(&box_reg); - } - RegionUninit(&clip_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } + else + { + if (pDst->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDst; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } + } + + if (!post_process) + { + return; + } + + memset(&box, 0, sizeof(box)); + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDst, pGC); + + if (cd == 1) + { + if (dirty_type != 0) + { + box.x1 = pDst->x + x; + box.y1 = pDst->y + y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(0, pDst->x + x, pDst->y + y, w, h); + rdpup_end_update(); + } + } + else if (cd == 2) + { + box.x1 = pDst->x + x; + box.y1 = pDst->y + y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(&box_reg, &box, 0); + RegionIntersect(&clip_reg, &clip_reg, &box_reg); + num_clips = REGION_NUM_RECTS(&clip_reg); + + if (num_clips > 0) + { + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, &clip_reg, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_send_area(0, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(&box_reg); + } + + RegionUninit(&clip_reg); + + if (reset_surface) + { + rdpup_switch_os_surface(-1); + } } diff --git a/xorg/X11R7.6/rdp/rdpPutImage.c b/xorg/X11R7.6/rdp/rdpPutImage.c index 798016f3..5fb28516 100644 --- a/xorg/X11R7.6/rdp/rdpPutImage.c +++ b/xorg/X11R7.6/rdp/rdpPutImage.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -46,143 +46,154 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ static void rdpPutImageOrg(DrawablePtr pDst, GCPtr pGC, int depth, int x, int y, - int w, int h, int leftPad, int format, char* pBits) + int w, int h, int leftPad, int format, char *pBits) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->PutImage(pDst, pGC, depth, x, y, w, h, leftPad, - format, pBits); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->PutImage(pDst, pGC, depth, x, y, w, h, leftPad, + format, pBits); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void rdpPutImage(DrawablePtr pDst, GCPtr pGC, int depth, int x, int y, - int w, int h, int leftPad, int format, char* pBits) + int w, int h, int leftPad, int format, char *pBits) { - RegionRec clip_reg; - int cd; - int j; - int reset_surface; - int post_process; - int got_id; - int dirty_type; - BoxRec box; - struct image_data id; + RegionRec clip_reg; + int cd; + int j; + int reset_surface; + int post_process; + int got_id; + int dirty_type; + BoxRec box; + struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; - RegionRec reg1; - RegionRec reg2; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; + RegionRec reg1; + RegionRec reg2; - LLOGLN(10, ("rdpPutImage:")); - LLOGLN(10, ("rdpPutImage: drawable id 0x%x", (int)(pDst->id))); + LLOGLN(10, ("rdpPutImage:")); + LLOGLN(10, ("rdpPutImage: drawable id 0x%x", (int)(pDst->id))); - /* do original call */ - rdpPutImageOrg(pDst, pGC, depth, x, y, w, h, leftPad, format, pBits); + /* do original call */ + rdpPutImageOrg(pDst, pGC, depth, x, y, w, h, leftPad, format, pBits); - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDst->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDst; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDst->type == DRAWABLE_PIXMAP) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpPutImage: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLY; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + pDstPixmap = (PixmapPtr)pDst; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpPutImage: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLY; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } } - } - else - { - if (pDst->type == DRAWABLE_WINDOW) + else { - pDstWnd = (WindowPtr)pDst; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } + if (pDst->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDst; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } } - } - if (!post_process) - { - return; - } - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDst, pGC); - if (cd == 1) - { - if (dirty_type != 0) + + if (!post_process) { - box.x1 = pDst->x + x; - box.y1 = pDst->y + y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); + return; } - else if (got_id) + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDst, pGC); + + if (cd == 1) { - rdpup_begin_update(); - rdpup_send_area(&id, pDst->x + x, pDst->y + y, w, h); - rdpup_end_update(); + if (dirty_type != 0) + { + box.x1 = pDst->x + x; + box.y1 = pDst->y + y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, pDst->x + x, pDst->y + y, w, h); + rdpup_end_update(); + } } - } - else if (cd == 2) - { - if (dirty_type != 0) + else if (cd == 2) { - box.x1 = pDst->x + x; - box.y1 = pDst->y + y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; - RegionInit(®1, &box, 0); - RegionInit(®2, NullBox, 0); - RegionCopy(®2, &clip_reg); - RegionIntersect(®1, ®1, ®2); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); - RegionUninit(®2); + if (dirty_type != 0) + { + box.x1 = pDst->x + x; + box.y1 = pDst->y + y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + RegionInit(®1, &box, 0); + RegionInit(®2, NullBox, 0); + RegionCopy(®2, &clip_reg); + RegionIntersect(®1, ®1, ®2); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + RegionUninit(®2); + } + else if (got_id) + { + rdpup_begin_update(); + + for (j = REGION_NUM_RECTS(&clip_reg) - 1; j >= 0; j--) + { + box = REGION_RECTS(&clip_reg)[j]; + rdpup_set_clip(box.x1, box.y1, (box.x2 - box.x1), (box.y2 - box.y1)); + rdpup_send_area(&id, pDst->x + x, pDst->y + y, w, h); + } + + rdpup_reset_clip(); + rdpup_end_update(); + } } - else if (got_id) + + RegionUninit(&clip_reg); + + if (reset_surface) { - rdpup_begin_update(); - for (j = REGION_NUM_RECTS(&clip_reg) - 1; j >= 0; j--) - { - box = REGION_RECTS(&clip_reg)[j]; - rdpup_set_clip(box.x1, box.y1, (box.x2 - box.x1), (box.y2 - box.y1)); - rdpup_send_area(&id, pDst->x + x, pDst->y + y, w, h); - } - rdpup_reset_clip(); - rdpup_end_update(); + rdpup_switch_os_surface(-1); } - } - RegionUninit(&clip_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } } diff --git a/xorg/X11R7.6/rdp/rdpSetSpans.c b/xorg/X11R7.6/rdp/rdpSetSpans.c index aab36f88..734d67ac 100644 --- a/xorg/X11R7.6/rdp/rdpSetSpans.c +++ b/xorg/X11R7.6/rdp/rdpSetSpans.c @@ -26,9 +26,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -45,107 +45,116 @@ extern int g_con_number; /* in rdpup.c */ /******************************************************************************/ void -rdpSetSpansOrg(DrawablePtr pDrawable, GCPtr pGC, char* psrc, - DDXPointPtr ppt, int* pwidth, int nspans, int fSorted) +rdpSetSpansOrg(DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) { - rdpGCPtr priv; - GCFuncs* oldFuncs; + rdpGCPtr priv; + GCFuncs *oldFuncs; - GC_OP_PROLOGUE(pGC); - pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); - GC_OP_EPILOGUE(pGC); + GC_OP_PROLOGUE(pGC); + pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + GC_OP_EPILOGUE(pGC); } /******************************************************************************/ void -rdpSetSpans(DrawablePtr pDrawable, GCPtr pGC, char* psrc, - DDXPointPtr ppt, int* pwidth, int nspans, int fSorted) +rdpSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) { - RegionRec clip_reg; - int cd; - int got_id; - int dirty_type; - int post_process; - int reset_surface; - struct image_data id; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; + RegionRec clip_reg; + int cd; + int got_id; + int dirty_type; + int post_process; + int reset_surface; + struct image_data id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; - LLOGLN(10, ("rdpSetSpans: todo")); + LLOGLN(10, ("rdpSetSpans: todo")); - /* do original call */ - rdpSetSpansOrg(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + /* do original call */ + rdpSetSpansOrg(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)pDrawable; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpSetSpans: gettig dirty")); - pDstPriv->is_dirty = 1; - pDirtyPriv = pDstPriv; - dirty_type = RDI_IMGLY; - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - } + pDstPixmap = (PixmapPtr)pDrawable; + pDstPriv = GETPIXPRIV(pDstPixmap); + + if (XRDP_IS_OS(pDstPriv)) + { + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpSetSpans: gettig dirty")); + pDstPriv->is_dirty = 1; + pDirtyPriv = pDstPriv; + dirty_type = RDI_IMGLY; + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } } - } - else - { - if (pDrawable->type == DRAWABLE_WINDOW) + else { - pDstWnd = (WindowPtr)pDrawable; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - } + if (pDrawable->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)pDrawable; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + } + } } - } - if (!post_process) - { - return; - } - RegionInit(&clip_reg, NullBox, 0); - cd = rdp_get_clip(&clip_reg, pDrawable, pGC); - if (cd == 1) - { - if (dirty_type != 0) + + if (!post_process) { + return; } - else if (got_id) + + RegionInit(&clip_reg, NullBox, 0); + cd = rdp_get_clip(&clip_reg, pDrawable, pGC); + + if (cd == 1) { + if (dirty_type != 0) + { + } + else if (got_id) + { + } } - } - else if (cd == 2) - { - if (dirty_type != 0) + else if (cd == 2) { + if (dirty_type != 0) + { + } + else if (got_id) + { + } } - else if (got_id) + + RegionUninit(&clip_reg); + + if (reset_surface) { + rdpup_switch_os_surface(-1); } - } - RegionUninit(&clip_reg); - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } } diff --git a/xorg/X11R7.6/rdp/rdpdraw.c b/xorg/X11R7.6/rdp/rdpdraw.c index 78b2aa3d..20876048 100644 --- a/xorg/X11R7.6/rdp/rdpdraw.c +++ b/xorg/X11R7.6/rdp/rdpdraw.c @@ -48,9 +48,9 @@ Xserver drawing ops and funcs #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern DevPrivateKeyRec g_rdpGCIndex; /* from rdpmain.c */ @@ -69,17 +69,17 @@ static int g_doing_font = 0; GCFuncs g_rdpGCFuncs = { - rdpValidateGC, rdpChangeGC, rdpCopyGC, rdpDestroyGC, rdpChangeClip, - rdpDestroyClip, rdpCopyClip + rdpValidateGC, rdpChangeGC, rdpCopyGC, rdpDestroyGC, rdpChangeClip, + rdpDestroyClip, rdpCopyClip }; GCOps g_rdpGCOps = { - rdpFillSpans, rdpSetSpans, rdpPutImage, rdpCopyArea, rdpCopyPlane, - rdpPolyPoint, rdpPolylines, rdpPolySegment, rdpPolyRectangle, - rdpPolyArc, rdpFillPolygon, rdpPolyFillRect, rdpPolyFillArc, - rdpPolyText8, rdpPolyText16, rdpImageText8, rdpImageText16, - rdpImageGlyphBlt, rdpPolyGlyphBlt, rdpPushPixels + rdpFillSpans, rdpSetSpans, rdpPutImage, rdpCopyArea, rdpCopyPlane, + rdpPolyPoint, rdpPolylines, rdpPolySegment, rdpPolyRectangle, + rdpPolyArc, rdpFillPolygon, rdpPolyFillRect, rdpPolyFillArc, + rdpPolyText8, rdpPolyText16, rdpImageText8, rdpImageText16, + rdpImageGlyphBlt, rdpPolyGlyphBlt, rdpPushPixels }; /******************************************************************************/ @@ -89,87 +89,95 @@ GCOps g_rdpGCOps = int rdp_get_clip(RegionPtr pRegion, DrawablePtr pDrawable, GCPtr pGC) { - WindowPtr pWindow; - RegionPtr temp; - BoxRec box; - int rv; + WindowPtr pWindow; + RegionPtr temp; + BoxRec box; + int rv; - rv = 0; - if (pDrawable->type == DRAWABLE_PIXMAP) - { - switch (pGC->clientClipType) + rv = 0; + + if (pDrawable->type == DRAWABLE_PIXMAP) { - case CT_NONE: - rv = 1; - break; - case CT_REGION: - rv = 2; - RegionCopy(pRegion, pGC->clientClip); - break; - default: - rdpLog("unimp clip type %d\n", pGC->clientClipType); - break; - } - if (rv == 2) /* check if the clip is the entire pixmap */ - { - box.x1 = 0; - box.y1 = 0; - box.x2 = pDrawable->width; - box.y2 = pDrawable->height; - if (RegionContainsRect(pRegion, &box) == rgnIN) - { - rv = 1; - } - } - } - else if (pDrawable->type == DRAWABLE_WINDOW) - { - pWindow = (WindowPtr)pDrawable; - if (pWindow->viewable) - { - if (pGC->subWindowMode == IncludeInferiors) - { - temp = &pWindow->borderClip; - } - else - { - temp = &pWindow->clipList; - } - if (RegionNotEmpty(temp)) - { switch (pGC->clientClipType) { - case CT_NONE: - rv = 2; - RegionCopy(pRegion, temp); - break; - case CT_REGION: - rv = 2; - RegionCopy(pRegion, pGC->clientClip); - RegionTranslate(pRegion, - pDrawable->x + pGC->clipOrg.x, - pDrawable->y + pGC->clipOrg.y); - RegionIntersect(pRegion, pRegion, temp); - break; - default: - rdpLog("unimp clip type %d\n", pGC->clientClipType); - break; + case CT_NONE: + rv = 1; + break; + case CT_REGION: + rv = 2; + RegionCopy(pRegion, pGC->clientClip); + break; + default: + rdpLog("unimp clip type %d\n", pGC->clientClipType); + break; } - if (rv == 2) /* check if the clip is the entire screen */ + + if (rv == 2) /* check if the clip is the entire pixmap */ { - box.x1 = 0; - box.y1 = 0; - box.x2 = g_rdpScreen.width; - box.y2 = g_rdpScreen.height; - if (RegionContainsRect(pRegion, &box) == rgnIN) - { - rv = 1; - } + box.x1 = 0; + box.y1 = 0; + box.x2 = pDrawable->width; + box.y2 = pDrawable->height; + + if (RegionContainsRect(pRegion, &box) == rgnIN) + { + rv = 1; + } } - } } - } - return rv; + else if (pDrawable->type == DRAWABLE_WINDOW) + { + pWindow = (WindowPtr)pDrawable; + + if (pWindow->viewable) + { + if (pGC->subWindowMode == IncludeInferiors) + { + temp = &pWindow->borderClip; + } + else + { + temp = &pWindow->clipList; + } + + if (RegionNotEmpty(temp)) + { + switch (pGC->clientClipType) + { + case CT_NONE: + rv = 2; + RegionCopy(pRegion, temp); + break; + case CT_REGION: + rv = 2; + RegionCopy(pRegion, pGC->clientClip); + RegionTranslate(pRegion, + pDrawable->x + pGC->clipOrg.x, + pDrawable->y + pGC->clipOrg.y); + RegionIntersect(pRegion, pRegion, temp); + break; + default: + rdpLog("unimp clip type %d\n", pGC->clientClipType); + break; + } + + if (rv == 2) /* check if the clip is the entire screen */ + { + box.x1 = 0; + box.y1 = 0; + box.x2 = g_rdpScreen.width; + box.y2 = g_rdpScreen.height; + + if (RegionContainsRect(pRegion, &box) == rgnIN) + { + rv = 1; + } + } + } + } + } + + return rv; } /******************************************************************************/ @@ -177,426 +185,456 @@ void GetTextBoundingBox(DrawablePtr pDrawable, FontPtr font, int x, int y, int n, BoxPtr pbox) { - int maxAscent; - int maxDescent; - int maxCharWidth; + int maxAscent; + int maxDescent; + int maxCharWidth; - if (FONTASCENT(font) > FONTMAXBOUNDS(font, ascent)) - { - maxAscent = FONTASCENT(font); - } - else - { - maxAscent = FONTMAXBOUNDS(font, ascent); - } - if (FONTDESCENT(font) > FONTMAXBOUNDS(font, descent)) - { - maxDescent = FONTDESCENT(font); - } - else - { - maxDescent = FONTMAXBOUNDS(font, descent); - } - if (FONTMAXBOUNDS(font, rightSideBearing) > - FONTMAXBOUNDS(font, characterWidth)) - { - maxCharWidth = FONTMAXBOUNDS(font, rightSideBearing); - } - else - { - maxCharWidth = FONTMAXBOUNDS(font, characterWidth); - } - pbox->x1 = pDrawable->x + x; - pbox->y1 = pDrawable->y + y - maxAscent; - pbox->x2 = pbox->x1 + maxCharWidth * n; - pbox->y2 = pbox->y1 + maxAscent + maxDescent; - if (FONTMINBOUNDS(font, leftSideBearing) < 0) - { - pbox->x1 += FONTMINBOUNDS(font, leftSideBearing); - } + if (FONTASCENT(font) > FONTMAXBOUNDS(font, ascent)) + { + maxAscent = FONTASCENT(font); + } + else + { + maxAscent = FONTMAXBOUNDS(font, ascent); + } + + if (FONTDESCENT(font) > FONTMAXBOUNDS(font, descent)) + { + maxDescent = FONTDESCENT(font); + } + else + { + maxDescent = FONTMAXBOUNDS(font, descent); + } + + if (FONTMAXBOUNDS(font, rightSideBearing) > + FONTMAXBOUNDS(font, characterWidth)) + { + maxCharWidth = FONTMAXBOUNDS(font, rightSideBearing); + } + else + { + maxCharWidth = FONTMAXBOUNDS(font, characterWidth); + } + + pbox->x1 = pDrawable->x + x; + pbox->y1 = pDrawable->y + y - maxAscent; + pbox->x2 = pbox->x1 + maxCharWidth * n; + pbox->y2 = pbox->y1 + maxAscent + maxDescent; + + if (FONTMINBOUNDS(font, leftSideBearing) < 0) + { + pbox->x1 += FONTMINBOUNDS(font, leftSideBearing); + } } /******************************************************************************/ #define GC_FUNC_PROLOGUE(_pGC) \ -{ \ - priv = (rdpGCPtr)(dixGetPrivateAddr(&(_pGC->devPrivates), &g_rdpGCIndex)); \ - (_pGC)->funcs = priv->funcs; \ - if (priv->ops != 0) \ - { \ - (_pGC)->ops = priv->ops; \ - } \ -} + { \ + priv = (rdpGCPtr)(dixGetPrivateAddr(&(_pGC->devPrivates), &g_rdpGCIndex)); \ + (_pGC)->funcs = priv->funcs; \ + if (priv->ops != 0) \ + { \ + (_pGC)->ops = priv->ops; \ + } \ + } /******************************************************************************/ #define GC_FUNC_EPILOGUE(_pGC) \ -{ \ - priv->funcs = (_pGC)->funcs; \ - (_pGC)->funcs = &g_rdpGCFuncs; \ - if (priv->ops != 0) \ - { \ - priv->ops = (_pGC)->ops; \ - (_pGC)->ops = &g_rdpGCOps; \ - } \ -} + { \ + priv->funcs = (_pGC)->funcs; \ + (_pGC)->funcs = &g_rdpGCFuncs; \ + if (priv->ops != 0) \ + { \ + priv->ops = (_pGC)->ops; \ + (_pGC)->ops = &g_rdpGCOps; \ + } \ + } /******************************************************************************/ static void rdpValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr d) { - rdpGCRec* priv; - int wrap; - RegionPtr pRegion; + rdpGCRec *priv; + int wrap; + RegionPtr pRegion; + + LLOGLN(10, ("rdpValidateGC:")); + GC_FUNC_PROLOGUE(pGC); + pGC->funcs->ValidateGC(pGC, changes, d); + + if (g_wrapPixmap) + { + wrap = 1; + } + else + { + wrap = (d->type == DRAWABLE_WINDOW) && ((WindowPtr)d)->viewable; + + if (wrap) + { + if (pGC->subWindowMode == IncludeInferiors) + { + pRegion = &(((WindowPtr)d)->borderClip); + } + else + { + pRegion = &(((WindowPtr)d)->clipList); + } + + wrap = RegionNotEmpty(pRegion); + } + } + + priv->ops = 0; - LLOGLN(10, ("rdpValidateGC:")); - GC_FUNC_PROLOGUE(pGC); - pGC->funcs->ValidateGC(pGC, changes, d); - if (g_wrapPixmap) - { - wrap = 1; - } - else - { - wrap = (d->type == DRAWABLE_WINDOW) && ((WindowPtr)d)->viewable; if (wrap) { - if (pGC->subWindowMode == IncludeInferiors) - { - pRegion = &(((WindowPtr)d)->borderClip); - } - else - { - pRegion = &(((WindowPtr)d)->clipList); - } - wrap = RegionNotEmpty(pRegion); + priv->ops = pGC->ops; } - } - priv->ops = 0; - if (wrap) - { - priv->ops = pGC->ops; - } - GC_FUNC_EPILOGUE(pGC); + + GC_FUNC_EPILOGUE(pGC); } /******************************************************************************/ static void rdpChangeGC(GCPtr pGC, unsigned long mask) { - rdpGCRec* priv; + rdpGCRec *priv; - LLOGLN(10, ("in rdpChangeGC")); - GC_FUNC_PROLOGUE(pGC); - pGC->funcs->ChangeGC(pGC, mask); - GC_FUNC_EPILOGUE(pGC); + LLOGLN(10, ("in rdpChangeGC")); + GC_FUNC_PROLOGUE(pGC); + pGC->funcs->ChangeGC(pGC, mask); + GC_FUNC_EPILOGUE(pGC); } /******************************************************************************/ static void rdpCopyGC(GCPtr src, unsigned long mask, GCPtr dst) { - rdpGCRec* priv; + rdpGCRec *priv; - LLOGLN(10, ("in rdpCopyGC")); - GC_FUNC_PROLOGUE(dst); - dst->funcs->CopyGC(src, mask, dst); - GC_FUNC_EPILOGUE(dst); + LLOGLN(10, ("in rdpCopyGC")); + GC_FUNC_PROLOGUE(dst); + dst->funcs->CopyGC(src, mask, dst); + GC_FUNC_EPILOGUE(dst); } /******************************************************************************/ static void rdpDestroyGC(GCPtr pGC) { - rdpGCRec* priv; + rdpGCRec *priv; - LLOGLN(10, ("in rdpDestroyGC")); - GC_FUNC_PROLOGUE(pGC); - pGC->funcs->DestroyGC(pGC); - GC_FUNC_EPILOGUE(pGC); + LLOGLN(10, ("in rdpDestroyGC")); + GC_FUNC_PROLOGUE(pGC); + pGC->funcs->DestroyGC(pGC); + GC_FUNC_EPILOGUE(pGC); } /******************************************************************************/ static void rdpChangeClip(GCPtr pGC, int type, pointer pValue, int nrects) { - rdpGCRec* priv; + rdpGCRec *priv; - LLOGLN(10, ("in rdpChangeClip")); - GC_FUNC_PROLOGUE(pGC); - pGC->funcs->ChangeClip(pGC, type, pValue, nrects); - GC_FUNC_EPILOGUE(pGC); + LLOGLN(10, ("in rdpChangeClip")); + GC_FUNC_PROLOGUE(pGC); + pGC->funcs->ChangeClip(pGC, type, pValue, nrects); + GC_FUNC_EPILOGUE(pGC); } /******************************************************************************/ static void rdpDestroyClip(GCPtr pGC) { - rdpGCRec* priv; + rdpGCRec *priv; - LLOGLN(10, ("in rdpDestroyClip")); - GC_FUNC_PROLOGUE(pGC); - pGC->funcs->DestroyClip(pGC); - GC_FUNC_EPILOGUE(pGC); + LLOGLN(10, ("in rdpDestroyClip")); + GC_FUNC_PROLOGUE(pGC); + pGC->funcs->DestroyClip(pGC); + GC_FUNC_EPILOGUE(pGC); } /******************************************************************************/ static void rdpCopyClip(GCPtr dst, GCPtr src) { - rdpGCRec* priv; + rdpGCRec *priv; - LLOGLN(0, ("in rdpCopyClip")); - GC_FUNC_PROLOGUE(dst); - dst->funcs->CopyClip(dst, src); - GC_FUNC_EPILOGUE(dst); + LLOGLN(0, ("in rdpCopyClip")); + GC_FUNC_PROLOGUE(dst); + dst->funcs->CopyClip(dst, src); + GC_FUNC_EPILOGUE(dst); } /******************************************************************************/ #define GC_OP_PROLOGUE(_pGC) \ -{ \ - priv = (rdpGCPtr)dixGetPrivateAddr(&(pGC->devPrivates), &g_rdpGCIndex); \ - oldFuncs = _pGC->funcs; \ - (_pGC)->funcs = priv->funcs; \ - (_pGC)->ops = priv->ops; \ -} + { \ + priv = (rdpGCPtr)dixGetPrivateAddr(&(pGC->devPrivates), &g_rdpGCIndex); \ + oldFuncs = _pGC->funcs; \ + (_pGC)->funcs = priv->funcs; \ + (_pGC)->ops = priv->ops; \ + } /******************************************************************************/ #define GC_OP_EPILOGUE(_pGC) \ -{ \ - priv->ops = (_pGC)->ops; \ - (_pGC)->funcs = oldFuncs; \ - (_pGC)->ops = &g_rdpGCOps; \ -} + { \ + priv->ops = (_pGC)->ops; \ + (_pGC)->funcs = oldFuncs; \ + (_pGC)->ops = &g_rdpGCOps; \ + } /******************************************************************************/ Bool rdpCloseScreen(int i, ScreenPtr pScreen) { - LLOGLN(10, ("in rdpCloseScreen")); - pScreen->CloseScreen = g_rdpScreen.CloseScreen; - pScreen->CreateGC = g_rdpScreen.CreateGC; - //pScreen->PaintWindowBackground = g_rdpScreen.PaintWindowBackground; - //pScreen->PaintWindowBorder = g_rdpScreen.PaintWindowBorder; - pScreen->CopyWindow = g_rdpScreen.CopyWindow; - pScreen->ClearToBackground = g_rdpScreen.ClearToBackground; - pScreen->RestoreAreas = g_rdpScreen.RestoreAreas; - return 1; + LLOGLN(10, ("in rdpCloseScreen")); + pScreen->CloseScreen = g_rdpScreen.CloseScreen; + pScreen->CreateGC = g_rdpScreen.CreateGC; + //pScreen->PaintWindowBackground = g_rdpScreen.PaintWindowBackground; + //pScreen->PaintWindowBorder = g_rdpScreen.PaintWindowBorder; + pScreen->CopyWindow = g_rdpScreen.CopyWindow; + pScreen->ClearToBackground = g_rdpScreen.ClearToBackground; + pScreen->RestoreAreas = g_rdpScreen.RestoreAreas; + return 1; } /******************************************************************************/ int -draw_item_add(rdpPixmapRec* priv, struct rdp_draw_item* di) +draw_item_add(rdpPixmapRec *priv, struct rdp_draw_item *di) { - if (priv->draw_item_tail == 0) - { - priv->draw_item_tail = di; - priv->draw_item_head = di; - } - else - { - di->prev = priv->draw_item_tail; - priv->draw_item_tail->next = di; - priv->draw_item_tail = di; - } - return 0; -} - -/******************************************************************************/ -int -draw_item_remove(rdpPixmapRec* priv, struct rdp_draw_item* di) -{ - if (di->prev != 0) - { - di->prev->next = di->next; - } - if (di->next != 0) - { - di->next->prev = di->prev; - } - if (priv->draw_item_head == di) - { - priv->draw_item_head = di->next; - } - if (priv->draw_item_tail == di) - { - priv->draw_item_tail = di->prev; - } - if (di->type == RDI_LINE) - { - if (di->u.line.segs != 0) + if (priv->draw_item_tail == 0) { - g_free(di->u.line.segs); - } - } - RegionDestroy(di->reg); - g_free(di); - return 0; -} - -/******************************************************************************/ -int -draw_item_remove_all(rdpPixmapRec* priv) -{ - struct rdp_draw_item* di; - - di = priv->draw_item_head; - while (di != 0) - { - draw_item_remove(priv, di); - di = priv->draw_item_head; - } - return 0; -} - -/******************************************************************************/ -int -draw_item_pack(rdpPixmapRec* priv) -{ - struct rdp_draw_item* di; - struct rdp_draw_item* di_prev; - -#if 1 - /* look for repeating draw types */ - if (priv->draw_item_head != 0) - { - if (priv->draw_item_head->next != 0) - { - di_prev = priv->draw_item_head; - di = priv->draw_item_head->next; - while (di != 0) - { - if ((di_prev->type == RDI_IMGLL) && (di->type == RDI_IMGLL)) - { - LLOGLN(10, ("draw_item_pack: packing RDI_IMGLL")); - RegionUnion(di_prev->reg, di_prev->reg, di->reg); - draw_item_remove(priv, di); - di = di_prev->next; - } - else if ((di_prev->type == RDI_IMGLY) && (di->type == RDI_IMGLY)) - { - LLOGLN(10, ("draw_item_pack: packing RDI_IMGLY")); - RegionUnion(di_prev->reg, di_prev->reg, di->reg); - draw_item_remove(priv, di); - di = di_prev->next; - } - else - { - di_prev = di; - di = di_prev->next; - } - } - } - } -#endif -#if 1 - /* subtract regions */ - if (priv->draw_item_tail != 0) - { - if (priv->draw_item_tail->prev != 0) - { - di = priv->draw_item_tail; - while (di->prev != 0) - { - /* skip subtract flag - * draw items like line can't be used to clear(subtract) previous - * draw items since they are not opaque - * eg they can not be the 'S' in 'D = M - S' - * the region for line draw items is the clip region */ - if ((di->flags & 1) == 0) - { - di_prev = di->prev; - while (di_prev != 0) - { - /* D = M - S */ - RegionSubtract(di_prev->reg, di_prev->reg, di->reg); - di_prev = di_prev->prev; - } - } - di = di->prev; - } - } - } -#endif -#if 1 - /* remove draw items with empty regions */ - di = priv->draw_item_head; - di_prev = 0; - while (di != 0) - { - if (!RegionNotEmpty(di->reg)) - { - LLOGLN(10, ("draw_item_pack: removing empty item type %d", di->type)); - draw_item_remove(priv, di); - di = di_prev == 0 ? priv->draw_item_head : di_prev->next; + priv->draw_item_tail = di; + priv->draw_item_head = di; } else { - di_prev = di; - di = di->next; + di->prev = priv->draw_item_tail; + priv->draw_item_tail->next = di; + priv->draw_item_tail = di; } - } -#endif - return 0; + + return 0; } /******************************************************************************/ int -draw_item_add_img_region(rdpPixmapRec* priv, RegionPtr reg, int opcode, +draw_item_remove(rdpPixmapRec *priv, struct rdp_draw_item *di) +{ + if (di->prev != 0) + { + di->prev->next = di->next; + } + + if (di->next != 0) + { + di->next->prev = di->prev; + } + + if (priv->draw_item_head == di) + { + priv->draw_item_head = di->next; + } + + if (priv->draw_item_tail == di) + { + priv->draw_item_tail = di->prev; + } + + if (di->type == RDI_LINE) + { + if (di->u.line.segs != 0) + { + g_free(di->u.line.segs); + } + } + + RegionDestroy(di->reg); + g_free(di); + return 0; +} + +/******************************************************************************/ +int +draw_item_remove_all(rdpPixmapRec *priv) +{ + struct rdp_draw_item *di; + + di = priv->draw_item_head; + + while (di != 0) + { + draw_item_remove(priv, di); + di = priv->draw_item_head; + } + + return 0; +} + +/******************************************************************************/ +int +draw_item_pack(rdpPixmapRec *priv) +{ + struct rdp_draw_item *di; + struct rdp_draw_item *di_prev; + +#if 1 + + /* look for repeating draw types */ + if (priv->draw_item_head != 0) + { + if (priv->draw_item_head->next != 0) + { + di_prev = priv->draw_item_head; + di = priv->draw_item_head->next; + + while (di != 0) + { + if ((di_prev->type == RDI_IMGLL) && (di->type == RDI_IMGLL)) + { + LLOGLN(10, ("draw_item_pack: packing RDI_IMGLL")); + RegionUnion(di_prev->reg, di_prev->reg, di->reg); + draw_item_remove(priv, di); + di = di_prev->next; + } + else if ((di_prev->type == RDI_IMGLY) && (di->type == RDI_IMGLY)) + { + LLOGLN(10, ("draw_item_pack: packing RDI_IMGLY")); + RegionUnion(di_prev->reg, di_prev->reg, di->reg); + draw_item_remove(priv, di); + di = di_prev->next; + } + else + { + di_prev = di; + di = di_prev->next; + } + } + } + } + +#endif +#if 1 + + /* subtract regions */ + if (priv->draw_item_tail != 0) + { + if (priv->draw_item_tail->prev != 0) + { + di = priv->draw_item_tail; + + while (di->prev != 0) + { + /* skip subtract flag + * draw items like line can't be used to clear(subtract) previous + * draw items since they are not opaque + * eg they can not be the 'S' in 'D = M - S' + * the region for line draw items is the clip region */ + if ((di->flags & 1) == 0) + { + di_prev = di->prev; + + while (di_prev != 0) + { + /* D = M - S */ + RegionSubtract(di_prev->reg, di_prev->reg, di->reg); + di_prev = di_prev->prev; + } + } + + di = di->prev; + } + } + } + +#endif +#if 1 + /* remove draw items with empty regions */ + di = priv->draw_item_head; + di_prev = 0; + + while (di != 0) + { + if (!RegionNotEmpty(di->reg)) + { + LLOGLN(10, ("draw_item_pack: removing empty item type %d", di->type)); + draw_item_remove(priv, di); + di = di_prev == 0 ? priv->draw_item_head : di_prev->next; + } + else + { + di_prev = di; + di = di->next; + } + } + +#endif + return 0; +} + +/******************************************************************************/ +int +draw_item_add_img_region(rdpPixmapRec *priv, RegionPtr reg, int opcode, int type) { - struct rdp_draw_item* di; + struct rdp_draw_item *di; - di = (struct rdp_draw_item*)g_malloc(sizeof(struct rdp_draw_item), 1); - di->type = type; - di->reg = RegionCreate(NullBox, 0); - RegionCopy(di->reg, reg); - di->u.img.opcode = opcode; - draw_item_add(priv, di); - return 0; + di = (struct rdp_draw_item *)g_malloc(sizeof(struct rdp_draw_item), 1); + di->type = type; + di->reg = RegionCreate(NullBox, 0); + RegionCopy(di->reg, reg); + di->u.img.opcode = opcode; + draw_item_add(priv, di); + return 0; } /******************************************************************************/ int -draw_item_add_fill_region(rdpPixmapRec* priv, RegionPtr reg, int color, +draw_item_add_fill_region(rdpPixmapRec *priv, RegionPtr reg, int color, int opcode) { - struct rdp_draw_item* di; + struct rdp_draw_item *di; - di = (struct rdp_draw_item*)g_malloc(sizeof(struct rdp_draw_item), 1); - di->type = RDI_FILL; - di->u.fill.fg_color = color; - di->u.fill.opcode = opcode; - di->reg = RegionCreate(NullBox, 0); - RegionCopy(di->reg, reg); - draw_item_add(priv, di); - return 0; + di = (struct rdp_draw_item *)g_malloc(sizeof(struct rdp_draw_item), 1); + di->type = RDI_FILL; + di->u.fill.fg_color = color; + di->u.fill.opcode = opcode; + di->reg = RegionCreate(NullBox, 0); + RegionCopy(di->reg, reg); + draw_item_add(priv, di); + return 0; } /******************************************************************************/ int -draw_item_add_line_region(rdpPixmapRec* priv, RegionPtr reg, int color, - int opcode, int width, xSegment* segs, int nseg, +draw_item_add_line_region(rdpPixmapRec *priv, RegionPtr reg, int color, + int opcode, int width, xSegment *segs, int nseg, int is_segment) { - struct rdp_draw_item* di; + struct rdp_draw_item *di; - LLOGLN(10, ("draw_item_add_line_region:")); - di = (struct rdp_draw_item*)g_malloc(sizeof(struct rdp_draw_item), 1); - di->type = RDI_LINE; - di->u.line.fg_color = color; - di->u.line.opcode = opcode; - di->u.line.width = width; - di->u.line.segs = (xSegment*)g_malloc(sizeof(xSegment) * nseg, 1); - memcpy(di->u.line.segs, segs, sizeof(xSegment) * nseg); - di->u.line.nseg = nseg; - if (is_segment) - { - di->u.line.flags = 1; - } - di->reg = RegionCreate(NullBox, 0); - di->flags |= 1; - RegionCopy(di->reg, reg); - draw_item_add(priv, di); - return 0; + LLOGLN(10, ("draw_item_add_line_region:")); + di = (struct rdp_draw_item *)g_malloc(sizeof(struct rdp_draw_item), 1); + di->type = RDI_LINE; + di->u.line.fg_color = color; + di->u.line.opcode = opcode; + di->u.line.width = width; + di->u.line.segs = (xSegment *)g_malloc(sizeof(xSegment) * nseg, 1); + memcpy(di->u.line.segs, segs, sizeof(xSegment) * nseg); + di->u.line.nseg = nseg; + + if (is_segment) + { + di->u.line.flags = 1; + } + + di->reg = RegionCreate(NullBox, 0); + di->flags |= 1; + RegionCopy(di->reg, reg); + draw_item_add(priv, di); + return 0; } /******************************************************************************/ @@ -604,317 +642,342 @@ PixmapPtr rdpCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, unsigned usage_hint) { - PixmapPtr rv; - rdpPixmapRec* priv; - int org_width; + PixmapPtr rv; + rdpPixmapRec *priv; + int org_width; - org_width = width; - /* width must be a multiple of 4 in rdp */ - width = (width + 3) & ~3; - LLOGLN(10, ("rdpCreatePixmap: width %d org_width %d depth %d screen depth %d", - width, org_width, depth, g_rdpScreen.depth)); - pScreen->CreatePixmap = g_rdpScreen.CreatePixmap; - rv = pScreen->CreatePixmap(pScreen, width, height, depth, usage_hint); - priv = GETPIXPRIV(rv); - priv->rdpindex = -1; - if ((rv->drawable.depth >= g_rdpScreen.depth) && - (org_width > 1) && (height > 1)) - { - priv->allocBytes = width * height * g_Bpp; - priv->rdpindex = rdpup_add_os_bitmap(rv, priv); - if (priv->rdpindex >= 0) + org_width = width; + /* width must be a multiple of 4 in rdp */ + width = (width + 3) & ~3; + LLOGLN(10, ("rdpCreatePixmap: width %d org_width %d depth %d screen depth %d", + width, org_width, depth, g_rdpScreen.depth)); + pScreen->CreatePixmap = g_rdpScreen.CreatePixmap; + rv = pScreen->CreatePixmap(pScreen, width, height, depth, usage_hint); + priv = GETPIXPRIV(rv); + priv->rdpindex = -1; + + if ((rv->drawable.depth >= g_rdpScreen.depth) && + (org_width > 1) && (height > 1)) { - priv->status = 1; - rdpup_create_os_surface(priv->rdpindex, width, height); + priv->allocBytes = width * height * g_Bpp; + priv->rdpindex = rdpup_add_os_bitmap(rv, priv); + + if (priv->rdpindex >= 0) + { + priv->status = 1; + rdpup_create_os_surface(priv->rdpindex, width, height); + } } - } - pScreen->ModifyPixmapHeader(rv, org_width, 0, 0, 0, 0, 0); - pScreen->CreatePixmap = rdpCreatePixmap; - return rv; + + pScreen->ModifyPixmapHeader(rv, org_width, 0, 0, 0, 0, 0); + pScreen->CreatePixmap = rdpCreatePixmap; + return rv; } -extern struct rdpup_os_bitmap* g_os_bitmaps; +extern struct rdpup_os_bitmap *g_os_bitmaps; /******************************************************************************/ Bool rdpDestroyPixmap(PixmapPtr pPixmap) { - Bool rv; - ScreenPtr pScreen; - rdpPixmapRec* priv; + Bool rv; + ScreenPtr pScreen; + rdpPixmapRec *priv; - LLOGLN(10, ("rdpDestroyPixmap:")); - priv = GETPIXPRIV(pPixmap); - LLOGLN(10, ("status %d refcnt %d", priv->status, pPixmap->refcnt)); - if (pPixmap->refcnt < 2) - { - if (XRDP_IS_OS(priv)) + LLOGLN(10, ("rdpDestroyPixmap:")); + priv = GETPIXPRIV(pPixmap); + LLOGLN(10, ("status %d refcnt %d", priv->status, pPixmap->refcnt)); + + if (pPixmap->refcnt < 2) { - rdpup_remove_os_bitmap(priv->rdpindex); - rdpup_delete_os_surface(priv->rdpindex); - draw_item_remove_all(priv); + if (XRDP_IS_OS(priv)) + { + rdpup_remove_os_bitmap(priv->rdpindex); + rdpup_delete_os_surface(priv->rdpindex); + draw_item_remove_all(priv); + } } - } - pScreen = pPixmap->drawable.pScreen; - pScreen->DestroyPixmap = g_rdpScreen.DestroyPixmap; - rv = pScreen->DestroyPixmap(pPixmap); - pScreen->DestroyPixmap = rdpDestroyPixmap; - return rv; + + pScreen = pPixmap->drawable.pScreen; + pScreen->DestroyPixmap = g_rdpScreen.DestroyPixmap; + rv = pScreen->DestroyPixmap(pPixmap); + pScreen->DestroyPixmap = rdpDestroyPixmap; + return rv; } /******************************************************************************/ Bool rdpCreateWindow(WindowPtr pWindow) { - ScreenPtr pScreen; - rdpWindowRec* priv; - Bool rv; + ScreenPtr pScreen; + rdpWindowRec *priv; + Bool rv; - LLOGLN(10, ("rdpCreateWindow:")); - priv = GETWINPRIV(pWindow); - LLOGLN(10, (" %p status %d", priv, priv->status)); - pScreen = pWindow->drawable.pScreen; - pScreen->CreateWindow = g_rdpScreen.CreateWindow; - rv = pScreen->CreateWindow(pWindow); - pScreen->CreateWindow = rdpCreateWindow; - if (g_use_rail) - { - } - return rv; + LLOGLN(10, ("rdpCreateWindow:")); + priv = GETWINPRIV(pWindow); + LLOGLN(10, (" %p status %d", priv, priv->status)); + pScreen = pWindow->drawable.pScreen; + pScreen->CreateWindow = g_rdpScreen.CreateWindow; + rv = pScreen->CreateWindow(pWindow); + pScreen->CreateWindow = rdpCreateWindow; + + if (g_use_rail) + { + } + + return rv; } /******************************************************************************/ Bool rdpDestroyWindow(WindowPtr pWindow) { - ScreenPtr pScreen; - rdpWindowRec* priv; - Bool rv; + ScreenPtr pScreen; + rdpWindowRec *priv; + Bool rv; - LLOGLN(10, ("rdpDestroyWindow:")); - priv = GETWINPRIV(pWindow); - pScreen = pWindow->drawable.pScreen; - pScreen->DestroyWindow = g_rdpScreen.DestroyWindow; - rv = pScreen->DestroyWindow(pWindow); - pScreen->DestroyWindow = rdpDestroyWindow; - if (g_use_rail) - { - } - return rv; + LLOGLN(10, ("rdpDestroyWindow:")); + priv = GETWINPRIV(pWindow); + pScreen = pWindow->drawable.pScreen; + pScreen->DestroyWindow = g_rdpScreen.DestroyWindow; + rv = pScreen->DestroyWindow(pWindow); + pScreen->DestroyWindow = rdpDestroyWindow; + + if (g_use_rail) + { + } + + return rv; } /******************************************************************************/ Bool rdpPositionWindow(WindowPtr pWindow, int x, int y) { - ScreenPtr pScreen; - rdpWindowRec* priv; - Bool rv; + ScreenPtr pScreen; + rdpWindowRec *priv; + Bool rv; - LLOGLN(10, ("rdpPositionWindow:")); - priv = GETWINPRIV(pWindow); - pScreen = pWindow->drawable.pScreen; - pScreen->PositionWindow = g_rdpScreen.PositionWindow; - rv = pScreen->PositionWindow(pWindow, x, y); - pScreen->PositionWindow = rdpPositionWindow; - if (g_use_rail) - { - if (priv->status == 1) + LLOGLN(10, ("rdpPositionWindow:")); + priv = GETWINPRIV(pWindow); + pScreen = pWindow->drawable.pScreen; + pScreen->PositionWindow = g_rdpScreen.PositionWindow; + rv = pScreen->PositionWindow(pWindow, x, y); + pScreen->PositionWindow = rdpPositionWindow; + + if (g_use_rail) { - LLOGLN(10, ("rdpPositionWindow:")); - LLOGLN(10, (" x %d y %d", x, y)); + if (priv->status == 1) + { + LLOGLN(10, ("rdpPositionWindow:")); + LLOGLN(10, (" x %d y %d", x, y)); + } } - } - return rv; + + return rv; } /******************************************************************************/ Bool rdpRealizeWindow(WindowPtr pWindow) { - ScreenPtr pScreen; - rdpWindowRec* priv; - Bool rv; + ScreenPtr pScreen; + rdpWindowRec *priv; + Bool rv; - LLOGLN(10, ("rdpRealizeWindow:")); - priv = GETWINPRIV(pWindow); - pScreen = pWindow->drawable.pScreen; - pScreen->RealizeWindow = g_rdpScreen.RealizeWindow; - rv = pScreen->RealizeWindow(pWindow); - pScreen->RealizeWindow = rdpRealizeWindow; - if (g_use_rail) - { - if ((pWindow != g_invalidate_window) && (pWindow->parent != 0)) + LLOGLN(10, ("rdpRealizeWindow:")); + priv = GETWINPRIV(pWindow); + pScreen = pWindow->drawable.pScreen; + pScreen->RealizeWindow = g_rdpScreen.RealizeWindow; + rv = pScreen->RealizeWindow(pWindow); + pScreen->RealizeWindow = rdpRealizeWindow; + + if (g_use_rail) { - if (XR_IS_ROOT(pWindow->parent)) - { - LLOGLN(10, ("rdpRealizeWindow:")); - LLOGLN(10, (" pWindow %p id 0x%x pWindow->parent %p id 0x%x x %d " - "y %d width %d height %d", - pWindow, pWindow->drawable.id, - pWindow->parent, pWindow->parent->drawable.id, - pWindow->drawable.x, pWindow->drawable.y, - pWindow->drawable.width, pWindow->drawable.height)); - priv->status = 1; - rdpup_create_window(pWindow, priv); - } + if ((pWindow != g_invalidate_window) && (pWindow->parent != 0)) + { + if (XR_IS_ROOT(pWindow->parent)) + { + LLOGLN(10, ("rdpRealizeWindow:")); + LLOGLN(10, (" pWindow %p id 0x%x pWindow->parent %p id 0x%x x %d " + "y %d width %d height %d", + pWindow, pWindow->drawable.id, + pWindow->parent, pWindow->parent->drawable.id, + pWindow->drawable.x, pWindow->drawable.y, + pWindow->drawable.width, pWindow->drawable.height)); + priv->status = 1; + rdpup_create_window(pWindow, priv); + } + } } - } - return rv; + + return rv; } /******************************************************************************/ Bool rdpUnrealizeWindow(WindowPtr pWindow) { - ScreenPtr pScreen; - rdpWindowRec* priv; - Bool rv; + ScreenPtr pScreen; + rdpWindowRec *priv; + Bool rv; - LLOGLN(10, ("rdpUnrealizeWindow:")); - priv = GETWINPRIV(pWindow); - pScreen = pWindow->drawable.pScreen; - pScreen->UnrealizeWindow = g_rdpScreen.UnrealizeWindow; - rv = pScreen->UnrealizeWindow(pWindow); - pScreen->UnrealizeWindow = rdpUnrealizeWindow; - if (g_use_rail) - { - if (priv->status == 1) + LLOGLN(10, ("rdpUnrealizeWindow:")); + priv = GETWINPRIV(pWindow); + pScreen = pWindow->drawable.pScreen; + pScreen->UnrealizeWindow = g_rdpScreen.UnrealizeWindow; + rv = pScreen->UnrealizeWindow(pWindow); + pScreen->UnrealizeWindow = rdpUnrealizeWindow; + + if (g_use_rail) { - LLOGLN(10, ("rdpUnrealizeWindow:")); - priv->status = 0; - rdpup_delete_window(pWindow, priv); + if (priv->status == 1) + { + LLOGLN(10, ("rdpUnrealizeWindow:")); + priv->status = 0; + rdpup_delete_window(pWindow, priv); + } } - } - return rv; + + return rv; } /******************************************************************************/ Bool rdpChangeWindowAttributes(WindowPtr pWindow, unsigned long mask) { - ScreenPtr pScreen; - rdpWindowRec* priv; - Bool rv; + ScreenPtr pScreen; + rdpWindowRec *priv; + Bool rv; - LLOGLN(10, ("rdpChangeWindowAttributes:")); - priv = GETWINPRIV(pWindow); - pScreen = pWindow->drawable.pScreen; - pScreen->ChangeWindowAttributes = g_rdpScreen.ChangeWindowAttributes; - rv = pScreen->ChangeWindowAttributes(pWindow, mask); - pScreen->ChangeWindowAttributes = rdpChangeWindowAttributes; - if (g_use_rail) - { - } - return rv; + LLOGLN(10, ("rdpChangeWindowAttributes:")); + priv = GETWINPRIV(pWindow); + pScreen = pWindow->drawable.pScreen; + pScreen->ChangeWindowAttributes = g_rdpScreen.ChangeWindowAttributes; + rv = pScreen->ChangeWindowAttributes(pWindow, mask); + pScreen->ChangeWindowAttributes = rdpChangeWindowAttributes; + + if (g_use_rail) + { + } + + return rv; } /******************************************************************************/ void rdpWindowExposures(WindowPtr pWindow, RegionPtr pRegion, RegionPtr pBSRegion) { - ScreenPtr pScreen; - rdpWindowRec* priv; + ScreenPtr pScreen; + rdpWindowRec *priv; - LLOGLN(10, ("rdpWindowExposures:")); - priv = GETWINPRIV(pWindow); - pScreen = pWindow->drawable.pScreen; - pScreen->WindowExposures = g_rdpScreen.WindowExposures; - pScreen->WindowExposures(pWindow, pRegion, pBSRegion); - if (g_use_rail) - { - } - pScreen->WindowExposures = rdpWindowExposures; + LLOGLN(10, ("rdpWindowExposures:")); + priv = GETWINPRIV(pWindow); + pScreen = pWindow->drawable.pScreen; + pScreen->WindowExposures = g_rdpScreen.WindowExposures; + pScreen->WindowExposures(pWindow, pRegion, pBSRegion); + + if (g_use_rail) + { + } + + pScreen->WindowExposures = rdpWindowExposures; } /******************************************************************************/ Bool rdpCreateGC(GCPtr pGC) { - rdpGCRec* priv; - Bool rv; + rdpGCRec *priv; + Bool rv; - LLOGLN(10, ("in rdpCreateGC\n")); - priv = GETGCPRIV(pGC); - g_pScreen->CreateGC = g_rdpScreen.CreateGC; - rv = g_pScreen->CreateGC(pGC); - if (rv) - { - priv->funcs = pGC->funcs; - priv->ops = 0; - pGC->funcs = &g_rdpGCFuncs; - } - else - { - rdpLog("error in rdpCreateGC, CreateGC failed\n"); - } - g_pScreen->CreateGC = rdpCreateGC; - return rv; + LLOGLN(10, ("in rdpCreateGC\n")); + priv = GETGCPRIV(pGC); + g_pScreen->CreateGC = g_rdpScreen.CreateGC; + rv = g_pScreen->CreateGC(pGC); + + if (rv) + { + priv->funcs = pGC->funcs; + priv->ops = 0; + pGC->funcs = &g_rdpGCFuncs; + } + else + { + rdpLog("error in rdpCreateGC, CreateGC failed\n"); + } + + g_pScreen->CreateGC = rdpCreateGC; + return rv; } /******************************************************************************/ void rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion) { - RegionRec reg; - RegionRec clip; - int dx; - int dy; - int i; - int j; - int num_clip_rects; - int num_reg_rects; - BoxRec box1; - BoxRec box2; + RegionRec reg; + RegionRec clip; + int dx; + int dy; + int i; + int j; + int num_clip_rects; + int num_reg_rects; + BoxRec box1; + BoxRec box2; - LLOGLN(10, ("in rdpCopyWindow")); - RegionInit(®, NullBox, 0); - RegionCopy(®, pOldRegion); - g_pScreen->CopyWindow = g_rdpScreen.CopyWindow; - g_pScreen->CopyWindow(pWin, ptOldOrg, pOldRegion); - RegionInit(&clip, NullBox, 0); - RegionCopy(&clip, &pWin->borderClip); - dx = pWin->drawable.x - ptOldOrg.x; - dy = pWin->drawable.y - ptOldOrg.y; - rdpup_begin_update(); - num_clip_rects = REGION_NUM_RECTS(&clip); - num_reg_rects = REGION_NUM_RECTS(®); - /* should maybe sort the rects instead of checking dy < 0 */ - /* If we can depend on the rects going from top to bottom, left - to right we are ok */ - if (dy < 0 || (dy == 0 && dx < 0)) - { - for (j = 0; j < num_clip_rects; j++) + LLOGLN(10, ("in rdpCopyWindow")); + RegionInit(®, NullBox, 0); + RegionCopy(®, pOldRegion); + g_pScreen->CopyWindow = g_rdpScreen.CopyWindow; + g_pScreen->CopyWindow(pWin, ptOldOrg, pOldRegion); + RegionInit(&clip, NullBox, 0); + RegionCopy(&clip, &pWin->borderClip); + dx = pWin->drawable.x - ptOldOrg.x; + dy = pWin->drawable.y - ptOldOrg.y; + rdpup_begin_update(); + num_clip_rects = REGION_NUM_RECTS(&clip); + num_reg_rects = REGION_NUM_RECTS(®); + + /* should maybe sort the rects instead of checking dy < 0 */ + /* If we can depend on the rects going from top to bottom, left + to right we are ok */ + if (dy < 0 || (dy == 0 && dx < 0)) { - box1 = REGION_RECTS(&clip)[j]; - rdpup_set_clip(box1.x1, box1.y1, box1.x2 - box1.x1, box1.y2 - box1.y1); - for (i = 0; i < num_reg_rects; i++) - { - box2 = REGION_RECTS(®)[i]; - rdpup_screen_blt(box2.x1 + dx, box2.y1 + dy, box2.x2 - box2.x1, - box2.y2 - box2.y1, box2.x1, box2.y1); - } + for (j = 0; j < num_clip_rects; j++) + { + box1 = REGION_RECTS(&clip)[j]; + rdpup_set_clip(box1.x1, box1.y1, box1.x2 - box1.x1, box1.y2 - box1.y1); + + for (i = 0; i < num_reg_rects; i++) + { + box2 = REGION_RECTS(®)[i]; + rdpup_screen_blt(box2.x1 + dx, box2.y1 + dy, box2.x2 - box2.x1, + box2.y2 - box2.y1, box2.x1, box2.y1); + } + } } - } - else - { - for (j = num_clip_rects - 1; j >= 0; j--) + else { - box1 = REGION_RECTS(&clip)[j]; - rdpup_set_clip(box1.x1, box1.y1, box1.x2 - box1.x1, box1.y2 - box1.y1); - for (i = num_reg_rects - 1; i >= 0; i--) - { - box2 = REGION_RECTS(®)[i]; - rdpup_screen_blt(box2.x1 + dx, box2.y1 + dy, box2.x2 - box2.x1, - box2.y2 - box2.y1, box2.x1, box2.y1); - } + for (j = num_clip_rects - 1; j >= 0; j--) + { + box1 = REGION_RECTS(&clip)[j]; + rdpup_set_clip(box1.x1, box1.y1, box1.x2 - box1.x1, box1.y2 - box1.y1); + + for (i = num_reg_rects - 1; i >= 0; i--) + { + box2 = REGION_RECTS(®)[i]; + rdpup_screen_blt(box2.x1 + dx, box2.y1 + dy, box2.x2 - box2.x1, + box2.y2 - box2.y1, box2.x1, box2.y1); + } + } } - } - rdpup_reset_clip(); - rdpup_end_update(); - RegionUninit(®); - RegionUninit(&clip); - g_pScreen->CopyWindow = rdpCopyWindow; + + rdpup_reset_clip(); + rdpup_end_update(); + RegionUninit(®); + RegionUninit(&clip); + g_pScreen->CopyWindow = rdpCopyWindow; } /******************************************************************************/ @@ -922,119 +985,130 @@ void rdpClearToBackground(WindowPtr pWin, int x, int y, int w, int h, Bool generateExposures) { - int j; - BoxRec box; - RegionRec reg; + int j; + BoxRec box; + RegionRec reg; - LLOGLN(10, ("in rdpClearToBackground")); - g_pScreen->ClearToBackground = g_rdpScreen.ClearToBackground; - g_pScreen->ClearToBackground(pWin, x, y, w, h, generateExposures); - if (!generateExposures) - { - if (w > 0 && h > 0) + LLOGLN(10, ("in rdpClearToBackground")); + g_pScreen->ClearToBackground = g_rdpScreen.ClearToBackground; + g_pScreen->ClearToBackground(pWin, x, y, w, h, generateExposures); + + if (!generateExposures) { - box.x1 = x; - box.y1 = y; - box.x2 = box.x1 + w; - box.y2 = box.y1 + h; + if (w > 0 && h > 0) + { + box.x1 = x; + box.y1 = y; + box.x2 = box.x1 + w; + box.y2 = box.y1 + h; + } + else + { + box.x1 = pWin->drawable.x; + box.y1 = pWin->drawable.y; + box.x2 = box.x1 + pWin->drawable.width; + box.y2 = box.y1 + pWin->drawable.height; + } + + RegionInit(®, &box, 0); + RegionIntersect(®, ®, &pWin->clipList); + rdpup_begin_update(); + + for (j = REGION_NUM_RECTS(®) - 1; j >= 0; j--) + { + box = REGION_RECTS(®)[j]; + rdpup_send_area(0, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_end_update(); + RegionUninit(®); } - else - { - box.x1 = pWin->drawable.x; - box.y1 = pWin->drawable.y; - box.x2 = box.x1 + pWin->drawable.width; - box.y2 = box.y1 + pWin->drawable.height; - } - RegionInit(®, &box, 0); - RegionIntersect(®, ®, &pWin->clipList); - rdpup_begin_update(); - for (j = REGION_NUM_RECTS(®) - 1; j >= 0; j--) - { - box = REGION_RECTS(®)[j]; - rdpup_send_area(0, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - rdpup_end_update(); - RegionUninit(®); - } - g_pScreen->ClearToBackground = rdpClearToBackground; + + g_pScreen->ClearToBackground = rdpClearToBackground; } /******************************************************************************/ RegionPtr rdpRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed) { - RegionRec reg; - RegionPtr rv; - int j; - BoxRec box; + RegionRec reg; + RegionPtr rv; + int j; + BoxRec box; - LLOGLN(10, ("in rdpRestoreAreas")); - RegionInit(®, NullBox, 0); - RegionCopy(®, prgnExposed); - g_pScreen->RestoreAreas = g_rdpScreen.RestoreAreas; - rv = g_pScreen->RestoreAreas(pWin, prgnExposed); - rdpup_begin_update(); - for (j = REGION_NUM_RECTS(®) - 1; j >= 0; j--) - { - box = REGION_RECTS(®)[j]; - rdpup_send_area(0, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - rdpup_end_update(); - RegionUninit(®); - g_pScreen->RestoreAreas = rdpRestoreAreas; - return rv; + LLOGLN(10, ("in rdpRestoreAreas")); + RegionInit(®, NullBox, 0); + RegionCopy(®, prgnExposed); + g_pScreen->RestoreAreas = g_rdpScreen.RestoreAreas; + rv = g_pScreen->RestoreAreas(pWin, prgnExposed); + rdpup_begin_update(); + + for (j = REGION_NUM_RECTS(®) - 1; j >= 0; j--) + { + box = REGION_RECTS(®)[j]; + rdpup_send_area(0, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_end_update(); + RegionUninit(®); + g_pScreen->RestoreAreas = rdpRestoreAreas; + return rv; } /******************************************************************************/ void rdpInstallColormap(ColormapPtr pmap) { - ColormapPtr oldpmap; + ColormapPtr oldpmap; - oldpmap = g_rdpInstalledColormap; - if (pmap != oldpmap) - { - if (oldpmap != (ColormapPtr)None) + oldpmap = g_rdpInstalledColormap; + + if (pmap != oldpmap) { - WalkTree(pmap->pScreen, TellLostMap, (char*)&oldpmap->mid); + if (oldpmap != (ColormapPtr)None) + { + WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); + } + + /* Install pmap */ + g_rdpInstalledColormap = pmap; + WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); + /*rfbSetClientColourMaps(0, 0);*/ } - /* Install pmap */ - g_rdpInstalledColormap = pmap; - WalkTree(pmap->pScreen, TellGainedMap, (char*)&pmap->mid); - /*rfbSetClientColourMaps(0, 0);*/ - } - /*g_rdpScreen.InstallColormap(pmap);*/ + + /*g_rdpScreen.InstallColormap(pmap);*/ } /******************************************************************************/ void rdpUninstallColormap(ColormapPtr pmap) { - ColormapPtr curpmap; + ColormapPtr curpmap; - curpmap = g_rdpInstalledColormap; - if (pmap == curpmap) - { - if (pmap->mid != pmap->pScreen->defColormap) + curpmap = g_rdpInstalledColormap; + + if (pmap == curpmap) { - //curpmap = (ColormapPtr)LookupIDByType(pmap->pScreen->defColormap, - // RT_COLORMAP); - //pmap->pScreen->InstallColormap(curpmap); + if (pmap->mid != pmap->pScreen->defColormap) + { + //curpmap = (ColormapPtr)LookupIDByType(pmap->pScreen->defColormap, + // RT_COLORMAP); + //pmap->pScreen->InstallColormap(curpmap); + } } - } } /******************************************************************************/ int -rdpListInstalledColormaps(ScreenPtr pScreen, Colormap* pmaps) +rdpListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) { - *pmaps = g_rdpInstalledColormap->mid; - return 1; + *pmaps = g_rdpInstalledColormap->mid; + return 1; } /******************************************************************************/ void -rdpStoreColors(ColormapPtr pmap, int ndef, xColorItem* pdefs) +rdpStoreColors(ColormapPtr pmap, int ndef, xColorItem *pdefs) { } @@ -1042,7 +1116,7 @@ rdpStoreColors(ColormapPtr pmap, int ndef, xColorItem* pdefs) Bool rdpSaveScreen(ScreenPtr pScreen, int on) { - return 1; + return 1; } /******************************************************************************/ @@ -1052,140 +1126,152 @@ rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { - BoxRec box; - PictureScreenPtr ps; - RegionRec reg1; - RegionRec reg2; - DrawablePtr p; - int dirty_type; - int j; - int num_clips; - int post_process; - int reset_surface; - int got_id; - int lx; - int ly; - WindowPtr pDstWnd; - PixmapPtr pDstPixmap; - rdpPixmapRec* pDstPriv; - rdpPixmapRec* pDirtyPriv; - struct image_data id; + BoxRec box; + PictureScreenPtr ps; + RegionRec reg1; + RegionRec reg2; + DrawablePtr p; + int dirty_type; + int j; + int num_clips; + int post_process; + int reset_surface; + int got_id; + int lx; + int ly; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec *pDstPriv; + rdpPixmapRec *pDirtyPriv; + struct image_data id; - LLOGLN(10, ("rdpComposite:")); - ps = GetPictureScreen(g_pScreen); - ps->Composite = g_rdpScreen.Composite; - ps->Composite(op, pSrc, pMask, pDst, xSrc, ySrc, - xMask, yMask, xDst, yDst, width, height); - ps->Composite = rdpComposite; + LLOGLN(10, ("rdpComposite:")); + ps = GetPictureScreen(g_pScreen); + ps->Composite = g_rdpScreen.Composite; + ps->Composite(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + ps->Composite = rdpComposite; - p = pDst->pDrawable; + p = pDst->pDrawable; - dirty_type = 0; - pDirtyPriv = 0; - post_process = 0; - reset_surface = 0; - got_id = 0; - if (p->type == DRAWABLE_PIXMAP) - { - pDstPixmap = (PixmapPtr)p; - pDstPriv = GETPIXPRIV(pDstPixmap); - if (XRDP_IS_OS(pDstPriv)) + dirty_type = 0; + pDirtyPriv = 0; + post_process = 0; + reset_surface = 0; + got_id = 0; + + if (p->type == DRAWABLE_PIXMAP) { - post_process = 1; - if (g_do_dirty_os) - { - LLOGLN(10, ("rdpComposite: gettig dirty")); - pDstPriv->is_dirty = 1; - dirty_type = g_doing_font ? RDI_IMGLL : RDI_IMGLY; - pDirtyPriv = pDstPriv; + pDstPixmap = (PixmapPtr)p; + pDstPriv = GETPIXPRIV(pDstPixmap); - } - else - { - rdpup_switch_os_surface(pDstPriv->rdpindex); - reset_surface = 1; - rdpup_get_pixmap_image_rect(pDstPixmap, &id); - got_id = 1; - LLOGLN(10, ("rdpComposite: offscreen")); - } - } - } - else - { - if (p->type == DRAWABLE_WINDOW) - { - pDstWnd = (WindowPtr)p; - if (pDstWnd->viewable) - { - post_process = 1; - rdpup_get_screen_image_rect(&id); - got_id = 1; - LLOGLN(10, ("rdpComposite: screen")); - } - } - } - if (!post_process) - { - return; - } - - if (pDst->clientClipType == CT_REGION) - { - box.x1 = p->x + xDst; - box.y1 = p->y + yDst; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; - RegionInit(®1, &box, 0); - RegionInit(®2, NullBox, 0); - RegionCopy(®2, pDst->clientClip); - lx = p->x + pDst->clipOrigin.x; - ly = p->y + pDst->clipOrigin.y; - RegionTranslate(®2, lx, ly); - RegionIntersect(®1, ®1, ®2); - if (dirty_type != 0) - { - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - } - else if (got_id) - { - num_clips = REGION_NUM_RECTS(®1); - if (num_clips > 0) - { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) + if (XRDP_IS_OS(pDstPriv)) { - box = REGION_RECTS(®1)[j]; - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + post_process = 1; + + if (g_do_dirty_os) + { + LLOGLN(10, ("rdpComposite: gettig dirty")); + pDstPriv->is_dirty = 1; + dirty_type = g_doing_font ? RDI_IMGLL : RDI_IMGLY; + pDirtyPriv = pDstPriv; + + } + else + { + rdpup_switch_os_surface(pDstPriv->rdpindex); + reset_surface = 1; + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + LLOGLN(10, ("rdpComposite: offscreen")); + } } - rdpup_end_update(); - } } - RegionUninit(®1); - RegionUninit(®2); - } - else - { - box.x1 = p->x + xDst; - box.y1 = p->y + yDst; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; - if (dirty_type != 0) + else { - RegionInit(®1, &box, 0); - draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); - RegionUninit(®1); + if (p->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)p; + + if (pDstWnd->viewable) + { + post_process = 1; + rdpup_get_screen_image_rect(&id); + got_id = 1; + LLOGLN(10, ("rdpComposite: screen")); + } + } } - else if (got_id) + + if (!post_process) { - rdpup_begin_update(); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - rdpup_end_update(); + return; + } + + if (pDst->clientClipType == CT_REGION) + { + box.x1 = p->x + xDst; + box.y1 = p->y + yDst; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + RegionInit(®1, &box, 0); + RegionInit(®2, NullBox, 0); + RegionCopy(®2, pDst->clientClip); + lx = p->x + pDst->clipOrigin.x; + ly = p->y + pDst->clipOrigin.y; + RegionTranslate(®2, lx, ly); + RegionIntersect(®1, ®1, ®2); + + if (dirty_type != 0) + { + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + } + else if (got_id) + { + num_clips = REGION_NUM_RECTS(®1); + + if (num_clips > 0) + { + rdpup_begin_update(); + + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®1)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_end_update(); + } + } + + RegionUninit(®1); + RegionUninit(®2); + } + else + { + box.x1 = p->x + xDst; + box.y1 = p->y + yDst; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + + if (dirty_type != 0) + { + RegionInit(®1, &box, 0); + draw_item_add_img_region(pDirtyPriv, ®1, GXcopy, dirty_type); + RegionUninit(®1); + } + else if (got_id) + { + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + } + + if (reset_surface) + { + rdpup_switch_os_surface(-1); } - } - if (reset_surface) - { - rdpup_switch_os_surface(-1); - } } /******************************************************************************/ @@ -1193,27 +1279,29 @@ void rdpGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists, GlyphListPtr lists, - GlyphPtr* glyphs) + GlyphPtr *glyphs) { - PictureScreenPtr ps; - int index; + PictureScreenPtr ps; + int index; - LLOGLN(10, ("rdpGlyphs:")); - LLOGLN(10, ("rdpGlyphs: nlists %d len %d", nlists, lists->len)); - rdpup_set_hints(1, 1); - g_doing_font = 1; - for (index = 0; index < lists->len; index++) - { - LLOGLN(10, (" index %d size %d refcnt %d width %d height %d", - index, (int)(glyphs[index]->size), (int)(glyphs[index]->refcnt), - glyphs[index]->info.width, glyphs[index]->info.height)); - } - ps = GetPictureScreen(g_pScreen); - ps->Glyphs = g_rdpScreen.Glyphs; - ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, - nlists, lists, glyphs); - ps->Glyphs = rdpGlyphs; - rdpup_set_hints(0, 1); - g_doing_font = 0; - LLOGLN(10, ("rdpGlyphs: out")); + LLOGLN(10, ("rdpGlyphs:")); + LLOGLN(10, ("rdpGlyphs: nlists %d len %d", nlists, lists->len)); + rdpup_set_hints(1, 1); + g_doing_font = 1; + + for (index = 0; index < lists->len; index++) + { + LLOGLN(10, (" index %d size %d refcnt %d width %d height %d", + index, (int)(glyphs[index]->size), (int)(glyphs[index]->refcnt), + glyphs[index]->info.width, glyphs[index]->info.height)); + } + + ps = GetPictureScreen(g_pScreen); + ps->Glyphs = g_rdpScreen.Glyphs; + ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, + nlists, lists, glyphs); + ps->Glyphs = rdpGlyphs; + rdpup_set_hints(0, 1); + g_doing_font = 0; + LLOGLN(10, ("rdpGlyphs: out")); } diff --git a/xorg/X11R7.6/rdp/rdpinput.c b/xorg/X11R7.6/rdp/rdpinput.c index 1256d0e0..b8e1746a 100644 --- a/xorg/X11R7.6/rdp/rdpinput.c +++ b/xorg/X11R7.6/rdp/rdpinput.c @@ -80,161 +80,161 @@ static int g_scroll_lock_down = 0; #define NUM_LOCK_KEY_CODE 77 #define N_PREDEFINED_KEYS \ - (sizeof(g_kbdMap) / (sizeof(KeySym) * GLYPHS_PER_KEY)) + (sizeof(g_kbdMap) / (sizeof(KeySym) * GLYPHS_PER_KEY)) /* Copied from Xvnc/lib/font/util/utilbitmap.c */ static unsigned char g_reverse_byte[0x100] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff }; static KeySym g_kbdMap[] = { - NoSymbol, NoSymbol, /* 8 */ - XK_Escape, NoSymbol, /* 9 */ - XK_1, XK_exclam, /* 10 */ - XK_2, XK_at, - XK_3, XK_numbersign, - XK_4, XK_dollar, - XK_5, XK_percent, - XK_6, XK_asciicircum, - XK_7, XK_ampersand, - XK_8, XK_asterisk, - XK_9, XK_parenleft, - XK_0, XK_parenright, - XK_minus, XK_underscore, /* 20 */ - XK_equal, XK_plus, - XK_BackSpace, NoSymbol, - XK_Tab, XK_ISO_Left_Tab, - XK_Q, NoSymbol, - XK_W, NoSymbol, - XK_E, NoSymbol, - XK_R, NoSymbol, - XK_T, NoSymbol, - XK_Y, NoSymbol, - XK_U, NoSymbol, /* 30 */ - XK_I, NoSymbol, - XK_O, NoSymbol, - XK_P, NoSymbol, - XK_bracketleft, XK_braceleft, - XK_bracketright, XK_braceright, - XK_Return, NoSymbol, - XK_Control_L, NoSymbol, - XK_A, NoSymbol, - XK_S, NoSymbol, - XK_D, NoSymbol, /* 40 */ - XK_F, NoSymbol, - XK_G, NoSymbol, - XK_H, NoSymbol, - XK_J, NoSymbol, - XK_K, NoSymbol, - XK_L, NoSymbol, - XK_semicolon, XK_colon, - XK_apostrophe, XK_quotedbl, - XK_grave, XK_asciitilde, - XK_Shift_L, NoSymbol, /* 50 */ - XK_backslash, XK_bar, - XK_Z, NoSymbol, - XK_X, NoSymbol, - XK_C, NoSymbol, - XK_V, NoSymbol, - XK_B, NoSymbol, - XK_N, NoSymbol, - XK_M, NoSymbol, - XK_comma, XK_less, - XK_period, XK_greater, /* 60 */ - XK_slash, XK_question, - XK_Shift_R, NoSymbol, - XK_KP_Multiply, NoSymbol, - XK_Alt_L, NoSymbol, - XK_space, NoSymbol, - XK_Caps_Lock, NoSymbol, - XK_F1, NoSymbol, - XK_F2, NoSymbol, - XK_F3, NoSymbol, - XK_F4, NoSymbol, /* 70 */ - XK_F5, NoSymbol, - XK_F6, NoSymbol, - XK_F7, NoSymbol, - XK_F8, NoSymbol, - XK_F9, NoSymbol, - XK_F10, NoSymbol, - XK_Num_Lock, NoSymbol, - XK_Scroll_Lock, NoSymbol, - XK_KP_Home, XK_KP_7, - XK_KP_Up, XK_KP_8, /* 80 */ - XK_KP_Prior, XK_KP_9, - XK_KP_Subtract, NoSymbol, - XK_KP_Left, XK_KP_4, - XK_KP_Begin, XK_KP_5, - XK_KP_Right, XK_KP_6, - XK_KP_Add, NoSymbol, - XK_KP_End, XK_KP_1, - XK_KP_Down, XK_KP_2, - XK_KP_Next, XK_KP_3, - XK_KP_Insert, XK_KP_0, /* 90 */ - XK_KP_Delete, XK_KP_Decimal, - NoSymbol, NoSymbol, - NoSymbol, NoSymbol, - NoSymbol, NoSymbol, - XK_F11, NoSymbol, - XK_F12, NoSymbol, - XK_Home, NoSymbol, - XK_Up, NoSymbol, - XK_Prior, NoSymbol, - XK_Left, NoSymbol, /* 100 */ - XK_Print, NoSymbol, - XK_Right, NoSymbol, - XK_End, NoSymbol, - XK_Down, NoSymbol, - XK_Next, NoSymbol, - XK_Insert, NoSymbol, - XK_Delete, NoSymbol, - XK_KP_Enter, NoSymbol, - XK_Control_R, NoSymbol, - XK_Pause, NoSymbol, /* 110 */ - XK_Print, NoSymbol, - XK_KP_Divide, NoSymbol, - XK_Alt_R, NoSymbol, - NoSymbol, NoSymbol, - XK_Super_L, NoSymbol, - XK_Super_R, NoSymbol, - XK_Menu, NoSymbol, - NoSymbol, NoSymbol, - NoSymbol, NoSymbol, - NoSymbol, NoSymbol, /* 120 */ - NoSymbol, NoSymbol + NoSymbol, NoSymbol, /* 8 */ + XK_Escape, NoSymbol, /* 9 */ + XK_1, XK_exclam, /* 10 */ + XK_2, XK_at, + XK_3, XK_numbersign, + XK_4, XK_dollar, + XK_5, XK_percent, + XK_6, XK_asciicircum, + XK_7, XK_ampersand, + XK_8, XK_asterisk, + XK_9, XK_parenleft, + XK_0, XK_parenright, + XK_minus, XK_underscore, /* 20 */ + XK_equal, XK_plus, + XK_BackSpace, NoSymbol, + XK_Tab, XK_ISO_Left_Tab, + XK_Q, NoSymbol, + XK_W, NoSymbol, + XK_E, NoSymbol, + XK_R, NoSymbol, + XK_T, NoSymbol, + XK_Y, NoSymbol, + XK_U, NoSymbol, /* 30 */ + XK_I, NoSymbol, + XK_O, NoSymbol, + XK_P, NoSymbol, + XK_bracketleft, XK_braceleft, + XK_bracketright, XK_braceright, + XK_Return, NoSymbol, + XK_Control_L, NoSymbol, + XK_A, NoSymbol, + XK_S, NoSymbol, + XK_D, NoSymbol, /* 40 */ + XK_F, NoSymbol, + XK_G, NoSymbol, + XK_H, NoSymbol, + XK_J, NoSymbol, + XK_K, NoSymbol, + XK_L, NoSymbol, + XK_semicolon, XK_colon, + XK_apostrophe, XK_quotedbl, + XK_grave, XK_asciitilde, + XK_Shift_L, NoSymbol, /* 50 */ + XK_backslash, XK_bar, + XK_Z, NoSymbol, + XK_X, NoSymbol, + XK_C, NoSymbol, + XK_V, NoSymbol, + XK_B, NoSymbol, + XK_N, NoSymbol, + XK_M, NoSymbol, + XK_comma, XK_less, + XK_period, XK_greater, /* 60 */ + XK_slash, XK_question, + XK_Shift_R, NoSymbol, + XK_KP_Multiply, NoSymbol, + XK_Alt_L, NoSymbol, + XK_space, NoSymbol, + XK_Caps_Lock, NoSymbol, + XK_F1, NoSymbol, + XK_F2, NoSymbol, + XK_F3, NoSymbol, + XK_F4, NoSymbol, /* 70 */ + XK_F5, NoSymbol, + XK_F6, NoSymbol, + XK_F7, NoSymbol, + XK_F8, NoSymbol, + XK_F9, NoSymbol, + XK_F10, NoSymbol, + XK_Num_Lock, NoSymbol, + XK_Scroll_Lock, NoSymbol, + XK_KP_Home, XK_KP_7, + XK_KP_Up, XK_KP_8, /* 80 */ + XK_KP_Prior, XK_KP_9, + XK_KP_Subtract, NoSymbol, + XK_KP_Left, XK_KP_4, + XK_KP_Begin, XK_KP_5, + XK_KP_Right, XK_KP_6, + XK_KP_Add, NoSymbol, + XK_KP_End, XK_KP_1, + XK_KP_Down, XK_KP_2, + XK_KP_Next, XK_KP_3, + XK_KP_Insert, XK_KP_0, /* 90 */ + XK_KP_Delete, XK_KP_Decimal, + NoSymbol, NoSymbol, + NoSymbol, NoSymbol, + NoSymbol, NoSymbol, + XK_F11, NoSymbol, + XK_F12, NoSymbol, + XK_Home, NoSymbol, + XK_Up, NoSymbol, + XK_Prior, NoSymbol, + XK_Left, NoSymbol, /* 100 */ + XK_Print, NoSymbol, + XK_Right, NoSymbol, + XK_End, NoSymbol, + XK_Down, NoSymbol, + XK_Next, NoSymbol, + XK_Insert, NoSymbol, + XK_Delete, NoSymbol, + XK_KP_Enter, NoSymbol, + XK_Control_R, NoSymbol, + XK_Pause, NoSymbol, /* 110 */ + XK_Print, NoSymbol, + XK_KP_Divide, NoSymbol, + XK_Alt_R, NoSymbol, + NoSymbol, NoSymbol, + XK_Super_L, NoSymbol, + XK_Super_R, NoSymbol, + XK_Menu, NoSymbol, + NoSymbol, NoSymbol, + NoSymbol, NoSymbol, + NoSymbol, NoSymbol, /* 120 */ + NoSymbol, NoSymbol }; #if 0 @@ -242,346 +242,369 @@ static KeySym g_kbdMap[] = static void rdpSendBell(void) { - DEBUG_OUT_INPUT(("rdpSendBell\n")); + DEBUG_OUT_INPUT(("rdpSendBell\n")); } #endif /******************************************************************************/ void -KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8* pModMap) +KbdDeviceInit(DeviceIntPtr pDevice, KeySymsPtr pKeySyms, CARD8 *pModMap) { - int i; + int i; - DEBUG_OUT_INPUT(("KbdDeviceInit\n")); - for (i = 0; i < MAP_LENGTH; i++) - { - pModMap[i] = NoSymbol; - } - pModMap[SHIFT_L_KEY_CODE] = ShiftMask; - pModMap[SHIFT_R_KEY_CODE] = ShiftMask; - pModMap[CAPS_LOCK_KEY_CODE] = LockMask; - pModMap[CONTROL_L_KEY_CODE] = ControlMask; - pModMap[CONTROL_R_KEY_CODE] = ControlMask; - pModMap[ALT_L_KEY_CODE] = Mod1Mask; - pModMap[ALT_R_KEY_CODE] = Mod1Mask; - pModMap[NUM_LOCK_KEY_CODE] = Mod2Mask; - pModMap[SUPER_L_KEY_CODE] = Mod4Mask; - pModMap[SUPER_R_KEY_CODE] = Mod4Mask; - pKeySyms->minKeyCode = MIN_KEY_CODE; - pKeySyms->maxKeyCode = MAX_KEY_CODE; - pKeySyms->mapWidth = GLYPHS_PER_KEY; - i = sizeof(KeySym) * MAP_LENGTH * GLYPHS_PER_KEY; - pKeySyms->map = (KeySym*)g_malloc(i, 1); - if (pKeySyms->map == 0) - { - rdpLog("KbdDeviceInit g_malloc failed\n"); - exit(1); - } - for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++) - { - pKeySyms->map[i] = NoSymbol; - } - for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) - { - pKeySyms->map[i] = g_kbdMap[i]; - } + DEBUG_OUT_INPUT(("KbdDeviceInit\n")); + + for (i = 0; i < MAP_LENGTH; i++) + { + pModMap[i] = NoSymbol; + } + + pModMap[SHIFT_L_KEY_CODE] = ShiftMask; + pModMap[SHIFT_R_KEY_CODE] = ShiftMask; + pModMap[CAPS_LOCK_KEY_CODE] = LockMask; + pModMap[CONTROL_L_KEY_CODE] = ControlMask; + pModMap[CONTROL_R_KEY_CODE] = ControlMask; + pModMap[ALT_L_KEY_CODE] = Mod1Mask; + pModMap[ALT_R_KEY_CODE] = Mod1Mask; + pModMap[NUM_LOCK_KEY_CODE] = Mod2Mask; + pModMap[SUPER_L_KEY_CODE] = Mod4Mask; + pModMap[SUPER_R_KEY_CODE] = Mod4Mask; + pKeySyms->minKeyCode = MIN_KEY_CODE; + pKeySyms->maxKeyCode = MAX_KEY_CODE; + pKeySyms->mapWidth = GLYPHS_PER_KEY; + i = sizeof(KeySym) * MAP_LENGTH * GLYPHS_PER_KEY; + pKeySyms->map = (KeySym *)g_malloc(i, 1); + + if (pKeySyms->map == 0) + { + rdpLog("KbdDeviceInit g_malloc failed\n"); + exit(1); + } + + for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++) + { + pKeySyms->map[i] = NoSymbol; + } + + for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) + { + pKeySyms->map[i] = g_kbdMap[i]; + } } /******************************************************************************/ void KbdDeviceOn(void) { - DEBUG_OUT_INPUT(("KbdDeviceOn\n")); + DEBUG_OUT_INPUT(("KbdDeviceOn\n")); } /******************************************************************************/ void KbdDeviceOff(void) { - DEBUG_OUT_INPUT(("KbdDeviceOff\n")); + DEBUG_OUT_INPUT(("KbdDeviceOff\n")); } /******************************************************************************/ void rdpBell(int volume, DeviceIntPtr pDev, pointer ctrl, int cls) { - ErrorF("rdpBell:\n"); + ErrorF("rdpBell:\n"); } /******************************************************************************/ void -rdpChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl* ctrl) +rdpChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl *ctrl) { - ErrorF("rdpChangeKeyboardControl:\n"); + ErrorF("rdpChangeKeyboardControl:\n"); } /******************************************************************************/ int rdpKeybdProc(DeviceIntPtr pDevice, int onoff) { - KeySymsRec keySyms; - CARD8 modMap[MAP_LENGTH]; - DevicePtr pDev; - XkbRMLVOSet set; + KeySymsRec keySyms; + CARD8 modMap[MAP_LENGTH]; + DevicePtr pDev; + XkbRMLVOSet set; - DEBUG_OUT_INPUT(("rdpKeybdProc\n")); - pDev = (DevicePtr)pDevice; - switch (onoff) - { - case DEVICE_INIT: - KbdDeviceInit(pDevice, &keySyms, modMap); - memset(&set, 0, sizeof(set)); - set.rules = "base"; - set.model = "pc104"; - set.layout = "us"; - set.variant = ""; - set.options = ""; - InitKeyboardDeviceStruct(pDevice, &set, rdpBell, - rdpChangeKeyboardControl); - //XkbDDXChangeControls(pDevice, 0, 0); - break; - case DEVICE_ON: - pDev->on = 1; - KbdDeviceOn(); - break; - case DEVICE_OFF: - pDev->on = 0; - KbdDeviceOff(); - break; - case DEVICE_CLOSE: - if (pDev->on) - { - KbdDeviceOff(); - } - break; - } - return Success; + DEBUG_OUT_INPUT(("rdpKeybdProc\n")); + pDev = (DevicePtr)pDevice; + + switch (onoff) + { + case DEVICE_INIT: + KbdDeviceInit(pDevice, &keySyms, modMap); + memset(&set, 0, sizeof(set)); + set.rules = "base"; + set.model = "pc104"; + set.layout = "us"; + set.variant = ""; + set.options = ""; + InitKeyboardDeviceStruct(pDevice, &set, rdpBell, + rdpChangeKeyboardControl); + //XkbDDXChangeControls(pDevice, 0, 0); + break; + case DEVICE_ON: + pDev->on = 1; + KbdDeviceOn(); + break; + case DEVICE_OFF: + pDev->on = 0; + KbdDeviceOff(); + break; + case DEVICE_CLOSE: + + if (pDev->on) + { + KbdDeviceOff(); + } + + break; + } + + return Success; } /******************************************************************************/ void -PtrDeviceControl(DeviceIntPtr dev, PtrCtrl* ctrl) +PtrDeviceControl(DeviceIntPtr dev, PtrCtrl *ctrl) { - DEBUG_OUT_INPUT(("PtrDeviceControl\n")); + DEBUG_OUT_INPUT(("PtrDeviceControl\n")); } /******************************************************************************/ void PtrDeviceInit(void) { - DEBUG_OUT_INPUT(("PtrDeviceInit\n")); + DEBUG_OUT_INPUT(("PtrDeviceInit\n")); } /******************************************************************************/ void PtrDeviceOn(DeviceIntPtr pDev) { - DEBUG_OUT_INPUT(("PtrDeviceOn\n")); + DEBUG_OUT_INPUT(("PtrDeviceOn\n")); } /******************************************************************************/ void PtrDeviceOff(void) { - DEBUG_OUT_INPUT(("PtrDeviceOff\n")); + DEBUG_OUT_INPUT(("PtrDeviceOff\n")); } /******************************************************************************/ static void -rdpMouseCtrl(DeviceIntPtr pDevice, PtrCtrl* pCtrl) +rdpMouseCtrl(DeviceIntPtr pDevice, PtrCtrl *pCtrl) { - ErrorF("rdpMouseCtrl:\n"); + ErrorF("rdpMouseCtrl:\n"); } /******************************************************************************/ int rdpMouseProc(DeviceIntPtr pDevice, int onoff) { - BYTE map[6]; - DevicePtr pDev; - Atom btn_labels[6]; - Atom axes_labels[2]; + BYTE map[6]; + DevicePtr pDev; + Atom btn_labels[6]; + Atom axes_labels[2]; - DEBUG_OUT_INPUT(("rdpMouseProc\n")); - pDev = (DevicePtr)pDevice; - switch (onoff) - { - case DEVICE_INIT: - PtrDeviceInit(); - map[0] = 0; - map[1] = 1; - map[2] = 2; - map[3] = 3; - map[4] = 4; - map[5] = 5; + DEBUG_OUT_INPUT(("rdpMouseProc\n")); + pDev = (DevicePtr)pDevice; - btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); - btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); - btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); - btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); - btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); + switch (onoff) + { + case DEVICE_INIT: + PtrDeviceInit(); + map[0] = 0; + map[1] = 1; + map[2] = 2; + map[3] = 3; + map[4] = 4; + map[5] = 5; - axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); - axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); + btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); - InitPointerDeviceStruct(pDev, map, 5, btn_labels, rdpMouseCtrl, - GetMotionHistorySize(), 2, axes_labels); + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); - break; - case DEVICE_ON: - pDev->on = 1; - PtrDeviceOn(pDevice); - break; - case DEVICE_OFF: - pDev->on = 0; - PtrDeviceOff(); - break; - case DEVICE_CLOSE: - if (pDev->on) - { - PtrDeviceOff(); - } - break; - } - return Success; + InitPointerDeviceStruct(pDev, map, 5, btn_labels, rdpMouseCtrl, + GetMotionHistorySize(), 2, axes_labels); + + break; + case DEVICE_ON: + pDev->on = 1; + PtrDeviceOn(pDevice); + break; + case DEVICE_OFF: + pDev->on = 0; + PtrDeviceOff(); + break; + case DEVICE_CLOSE: + + if (pDev->on) + { + PtrDeviceOff(); + } + + break; + } + + return Success; } /******************************************************************************/ Bool -rdpCursorOffScreen(ScreenPtr* ppScreen, int* x, int* y) +rdpCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) { - DEBUG_OUT_INPUT(("rdpCursorOffScreen\n")); - return 0; + DEBUG_OUT_INPUT(("rdpCursorOffScreen\n")); + return 0; } /******************************************************************************/ void rdpCrossScreen(ScreenPtr pScreen, Bool entering) { - DEBUG_OUT_INPUT(("rdpCrossScreen\n")); + DEBUG_OUT_INPUT(("rdpCrossScreen\n")); } /******************************************************************************/ void rdpPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScr, int x, int y) { - ErrorF("rdpPointerWarpCursor:\n"); - miPointerWarpCursor(pDev, pScr, x, y); + ErrorF("rdpPointerWarpCursor:\n"); + miPointerWarpCursor(pDev, pScr, x, y); } /******************************************************************************/ void -rdpPointerEnqueueEvent(DeviceIntPtr pDev, InternalEvent* event) +rdpPointerEnqueueEvent(DeviceIntPtr pDev, InternalEvent *event) { - ErrorF("rdpPointerEnqueueEvent:\n"); + ErrorF("rdpPointerEnqueueEvent:\n"); } /******************************************************************************/ void rdpPointerNewEventScreen(DeviceIntPtr pDev, ScreenPtr pScr, Bool fromDIX) { - ErrorF("rdpPointerNewEventScreen:\n"); + ErrorF("rdpPointerNewEventScreen:\n"); } /******************************************************************************/ Bool rdpSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScr, CursorPtr pCurs) { - DEBUG_OUT_INPUT(("rdpSpriteRealizeCursor\n")); - return 1; + DEBUG_OUT_INPUT(("rdpSpriteRealizeCursor\n")); + return 1; } /******************************************************************************/ Bool rdpSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScr, CursorPtr pCurs) { - DEBUG_OUT_INPUT(("hi rdpSpriteUnrealizeCursor\n")); - return 1; + DEBUG_OUT_INPUT(("hi rdpSpriteUnrealizeCursor\n")); + return 1; } /******************************************************************************/ int -get_pixel_safe(char* data, int x, int y, int width, int height, int bpp) +get_pixel_safe(char *data, int x, int y, int width, int height, int bpp) { - int start; - int shift; - int c; + int start; + int shift; + int c; - if (x < 0) - { - return 0; - } - if (y < 0) - { - return 0; - } - if (x >= width) - { - return 0; - } - if (y >= height) - { - return 0; - } - if (bpp == 1) - { - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - c = (unsigned char)(data[start]); + if (x < 0) + { + return 0; + } + + if (y < 0) + { + return 0; + } + + if (x >= width) + { + return 0; + } + + if (y >= height) + { + return 0; + } + + if (bpp == 1) + { + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + c = (unsigned char)(data[start]); #if (X_BYTE_ORDER == X_LITTLE_ENDIAN) - return (g_reverse_byte[c] & (0x80 >> shift)) != 0; + return (g_reverse_byte[c] & (0x80 >> shift)) != 0; #else - return (c & (0x80 >> shift)) != 0; + return (c & (0x80 >> shift)) != 0; #endif - } - return 0; + } + + return 0; } /******************************************************************************/ void -set_pixel_safe(char* data, int x, int y, int width, int height, int bpp, +set_pixel_safe(char *data, int x, int y, int width, int height, int bpp, int pixel) { - int start; - int shift; + int start; + int shift; - if (x < 0) - { - return; - } - if (y < 0) - { - return; - } - if (x >= width) - { - return; - } - if (y >= height) - { - return; - } - if (bpp == 1) - { - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - if (pixel & 1) + if (x < 0) { - data[start] = data[start] | (0x80 >> shift); + return; } - else + + if (y < 0) { - data[start] = data[start] & ~(0x80 >> shift); + return; + } + + if (x >= width) + { + return; + } + + if (y >= height) + { + return; + } + + if (bpp == 1) + { + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + + if (pixel & 1) + { + data[start] = data[start] | (0x80 >> shift); + } + else + { + data[start] = data[start] & ~(0x80 >> shift); + } + } + else if (bpp == 24) + { + *(data + (3 * (y * width + x)) + 0) = pixel >> 0; + *(data + (3 * (y * width + x)) + 1) = pixel >> 8; + *(data + (3 * (y * width + x)) + 2) = pixel >> 16; } - } - else if (bpp == 24) - { - *(data + (3 * (y * width + x)) + 0) = pixel >> 0; - *(data + (3 * (y * width + x)) + 1) = pixel >> 8; - *(data + (3 * (y * width + x)) + 2) = pixel >> 16; - } } /******************************************************************************/ @@ -589,217 +612,231 @@ void rdpSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScr, CursorPtr pCurs, int x, int y) { - char cur_data[32 * (32 * 3)]; - char cur_mask[32 * (32 / 8)]; - char* mask; - char* data; - int i; - int j; - int w; - int h; - int p; - int xhot; - int yhot; - int paddedRowBytes; - int fgcolor; - int bgcolor; + char cur_data[32 * (32 * 3)]; + char cur_mask[32 * (32 / 8)]; + char *mask; + char *data; + int i; + int j; + int w; + int h; + int p; + int xhot; + int yhot; + int paddedRowBytes; + int fgcolor; + int bgcolor; - if (pCurs == 0) - { - return; - } - if (pCurs->bits == 0) - { - return; - } - w = pCurs->bits->width; - h = pCurs->bits->height; - paddedRowBytes = PixmapBytePad(w, 1); - xhot = pCurs->bits->xhot; - yhot = pCurs->bits->yhot; - /* ErrorF("xhot %d yhot %d\n", xhot, yhot); */ - data = (char*)(pCurs->bits->source); - mask = (char*)(pCurs->bits->mask); - fgcolor = (((pCurs->foreRed >> 8) & 0xff) << 16) | - (((pCurs->foreGreen >> 8) & 0xff) << 8) | - ((pCurs->foreBlue >> 8) & 0xff); - bgcolor = (((pCurs->backRed >> 8) & 0xff) << 16) | - (((pCurs->backGreen >> 8) & 0xff) << 8) | - ((pCurs->backBlue >> 8) & 0xff); - memset(cur_data, 0, sizeof(cur_data)); - memset(cur_mask, 0, sizeof(cur_mask)); - for (j = 0; j < 32; j++) - { - for (i = 0; i < 32; i++) + if (pCurs == 0) { - p = get_pixel_safe(mask, i, j, paddedRowBytes * 8, h, 1); - set_pixel_safe(cur_mask, i, 31 - j, 32, 32, 1, !p); - if (p != 0) - { - p = get_pixel_safe(data, i, j, paddedRowBytes * 8, h, 1); - p = p ? fgcolor : bgcolor; - set_pixel_safe(cur_data, i, 31 - j, 32, 32, 24, p); - } + return; } - } - rdpup_begin_update(); - rdpup_set_cursor(xhot, yhot, cur_data, cur_mask); - rdpup_end_update(); + + if (pCurs->bits == 0) + { + return; + } + + w = pCurs->bits->width; + h = pCurs->bits->height; + paddedRowBytes = PixmapBytePad(w, 1); + xhot = pCurs->bits->xhot; + yhot = pCurs->bits->yhot; + /* ErrorF("xhot %d yhot %d\n", xhot, yhot); */ + data = (char *)(pCurs->bits->source); + mask = (char *)(pCurs->bits->mask); + fgcolor = (((pCurs->foreRed >> 8) & 0xff) << 16) | + (((pCurs->foreGreen >> 8) & 0xff) << 8) | + ((pCurs->foreBlue >> 8) & 0xff); + bgcolor = (((pCurs->backRed >> 8) & 0xff) << 16) | + (((pCurs->backGreen >> 8) & 0xff) << 8) | + ((pCurs->backBlue >> 8) & 0xff); + memset(cur_data, 0, sizeof(cur_data)); + memset(cur_mask, 0, sizeof(cur_mask)); + + for (j = 0; j < 32; j++) + { + for (i = 0; i < 32; i++) + { + p = get_pixel_safe(mask, i, j, paddedRowBytes * 8, h, 1); + set_pixel_safe(cur_mask, i, 31 - j, 32, 32, 1, !p); + + if (p != 0) + { + p = get_pixel_safe(data, i, j, paddedRowBytes * 8, h, 1); + p = p ? fgcolor : bgcolor; + set_pixel_safe(cur_data, i, 31 - j, 32, 32, 24, p); + } + } + } + + rdpup_begin_update(); + rdpup_set_cursor(xhot, yhot, cur_data, cur_mask); + rdpup_end_update(); } /******************************************************************************/ void rdpSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScr, int x, int y) { - DEBUG_OUT_INPUT(("hi rdpSpriteMoveCursor\n")); + DEBUG_OUT_INPUT(("hi rdpSpriteMoveCursor\n")); } /******************************************************************************/ Bool rdpSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr) { - ErrorF("rdpSpriteDeviceCursorInitialize:\n"); - return 1; + ErrorF("rdpSpriteDeviceCursorInitialize:\n"); + return 1; } /******************************************************************************/ void rdpSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr) { - ErrorF("rdpSpriteDeviceCursorCleanup:\n"); + ErrorF("rdpSpriteDeviceCursorCleanup:\n"); } /******************************************************************************/ static void rdpEnqueueMotion(int x, int y) { - int i; - int n; - int valuators[2]; - EventListPtr rdp_events; - xEvent* pev; + int i; + int n; + int valuators[2]; + EventListPtr rdp_events; + xEvent *pev; # if 0 - if (x < 128) - { - rdpup_begin_update(); - rdpup_send_area(0, 0, 1024, 768); - rdpup_end_update(); - } -#endif - miPointerSetPosition(g_pointer, &x, &y); - valuators[0] = x; - valuators[1] = y; - GetEventList(&rdp_events); - n = GetPointerEvents(rdp_events, g_pointer, MotionNotify, 0, - POINTER_ABSOLUTE | POINTER_SCREEN, - 0, 2, valuators); - for (i = 0; i < n; i++) - { - pev = (rdp_events + i)->event; - mieqEnqueue(g_pointer, (InternalEvent*)pev); - } + if (x < 128) + { + rdpup_begin_update(); + rdpup_send_area(0, 0, 1024, 768); + rdpup_end_update(); + } + +#endif + miPointerSetPosition(g_pointer, &x, &y); + valuators[0] = x; + valuators[1] = y; + + GetEventList(&rdp_events); + n = GetPointerEvents(rdp_events, g_pointer, MotionNotify, 0, + POINTER_ABSOLUTE | POINTER_SCREEN, + 0, 2, valuators); + + for (i = 0; i < n; i++) + { + pev = (rdp_events + i)->event; + mieqEnqueue(g_pointer, (InternalEvent *)pev); + } } /******************************************************************************/ static void rdpEnqueueButton(int type, int buttons) { - int i; - int n; - EventListPtr rdp_events; - xEvent* pev; + int i; + int n; + EventListPtr rdp_events; + xEvent *pev; - i = GetEventList(&rdp_events); - n = GetPointerEvents(rdp_events, g_pointer, type, buttons, 0, 0, 0, 0); - for (i = 0; i < n; i++) - { - pev = (rdp_events + i)->event; - mieqEnqueue(g_pointer, (InternalEvent*)pev); - } + i = GetEventList(&rdp_events); + n = GetPointerEvents(rdp_events, g_pointer, type, buttons, 0, 0, 0, 0); + + for (i = 0; i < n; i++) + { + pev = (rdp_events + i)->event; + mieqEnqueue(g_pointer, (InternalEvent *)pev); + } } /******************************************************************************/ static void rdpEnqueueKey(int type, int scancode) { - int i; - int n; - EventListPtr rdp_events; - xEvent* pev; + int i; + int n; + EventListPtr rdp_events; + xEvent *pev; - i = GetEventList(&rdp_events); - n = GetKeyboardEvents(rdp_events, g_keyboard, type, scancode); - for (i = 0; i < n; i++) - { - pev = (rdp_events + i)->event; - mieqEnqueue(g_keyboard, (InternalEvent*)pev); - } + i = GetEventList(&rdp_events); + n = GetKeyboardEvents(rdp_events, g_keyboard, type, scancode); + + for (i = 0; i < n; i++) + { + pev = (rdp_events + i)->event; + mieqEnqueue(g_keyboard, (InternalEvent *)pev); + } } /******************************************************************************/ void PtrAddEvent(int buttonMask, int x, int y) { - int i; - int type; - int buttons; + int i; + int type; + int buttons; - rdpEnqueueMotion(x, y); - for (i = 0; i < 5; i++) - { - if ((buttonMask ^ g_old_button_mask) & (1 << i)) + rdpEnqueueMotion(x, y); + + for (i = 0; i < 5; i++) { - if (buttonMask & (1 << i)) - { - type = ButtonPress; - buttons = i + 1; - rdpEnqueueButton(type, buttons); - } - else - { - type = ButtonRelease; - buttons = i + 1; - rdpEnqueueButton(type, buttons); - } + if ((buttonMask ^ g_old_button_mask) & (1 << i)) + { + if (buttonMask & (1 << i)) + { + type = ButtonPress; + buttons = i + 1; + rdpEnqueueButton(type, buttons); + } + else + { + type = ButtonRelease; + buttons = i + 1; + rdpEnqueueButton(type, buttons); + } + } } - } - g_old_button_mask = buttonMask; + + g_old_button_mask = buttonMask; } /******************************************************************************/ void check_keysa(void) { - if (g_ctrl_down != 0) - { - rdpEnqueueKey(KeyRelease, g_ctrl_down); - g_ctrl_down = 0; - } - if (g_alt_down != 0) - { - rdpEnqueueKey(KeyRelease, g_alt_down); - g_alt_down = 0; - } - if (g_shift_down != 0) - { - rdpEnqueueKey(KeyRelease, g_shift_down); - g_shift_down = 0; - } + if (g_ctrl_down != 0) + { + rdpEnqueueKey(KeyRelease, g_ctrl_down); + g_ctrl_down = 0; + } + + if (g_alt_down != 0) + { + rdpEnqueueKey(KeyRelease, g_alt_down); + g_alt_down = 0; + } + + if (g_shift_down != 0) + { + rdpEnqueueKey(KeyRelease, g_shift_down); + g_shift_down = 0; + } } /******************************************************************************/ void sendDownUpKeyEvent(int type, int x_scancode) { - /* if type is keydown, send keydown + keyup */ - /* this allows us to ignore keyup events */ - if (type == KeyPress) - { - rdpEnqueueKey(KeyPress, x_scancode); - rdpEnqueueKey(KeyRelease, x_scancode); - } + /* if type is keydown, send keydown + keyup */ + /* this allows us to ignore keyup events */ + if (type == KeyPress) + { + rdpEnqueueKey(KeyPress, x_scancode); + rdpEnqueueKey(KeyRelease, x_scancode); + } } /** @@ -812,182 +849,192 @@ sendDownUpKeyEvent(int type, int x_scancode) void KbdAddEvent(int down, int param1, int param2, int param3, int param4) { - int rdp_scancode; - int x_scancode; - int is_ext; - int is_spe; - int type; + int rdp_scancode; + int x_scancode; + int is_ext; + int is_spe; + int type; #if 0 - fprintf(stderr, "down=0x%x param1=0x%x param2=0x%x param3=0x%x " - "param4=0x%x\n", down, param1, param2, param3, param4); + fprintf(stderr, "down=0x%x param1=0x%x param2=0x%x param3=0x%x " + "param4=0x%x\n", down, param1, param2, param3, param4); #endif - type = down ? KeyPress : KeyRelease; - rdp_scancode = param3; - is_ext = param4 & 256; /* 0x100 */ - is_spe = param4 & 512; /* 0x200 */ - x_scancode = 0; + type = down ? KeyPress : KeyRelease; + rdp_scancode = param3; + is_ext = param4 & 256; /* 0x100 */ + is_spe = param4 & 512; /* 0x200 */ + x_scancode = 0; - switch (rdp_scancode) - { - case 58: /* caps lock */ - case 42: /* left shift */ - case 54: /* right shift */ - case 70: /* scroll lock */ - x_scancode = rdp_scancode + MIN_KEY_CODE; - if (x_scancode > 0) - { - rdpEnqueueKey(type, x_scancode); - } + switch (rdp_scancode) + { + case 58: /* caps lock */ + case 42: /* left shift */ + case 54: /* right shift */ + case 70: /* scroll lock */ + x_scancode = rdp_scancode + MIN_KEY_CODE; - break; + if (x_scancode > 0) + { + rdpEnqueueKey(type, x_scancode); + } - case 56: /* left - right alt button */ - if (is_ext) - { - x_scancode = 113; /* right alt button */ - } - else - { - x_scancode = 64; /* left alt button */ - } + break; - rdpEnqueueKey(type, x_scancode); - break; + case 56: /* left - right alt button */ - case 15: /* tab */ - if (!down && !g_tab_down) - { - check_keysa(); /* leave x_scancode 0 here, we don't want the tab key up */ - } - else - { - sendDownUpKeyEvent(type, 23); - } + if (is_ext) + { + x_scancode = 113; /* right alt button */ + } + else + { + x_scancode = 64; /* left alt button */ + } - g_tab_down = down; - break; + rdpEnqueueKey(type, x_scancode); + break; - case 29: /* left or right ctrl */ - /* this is to handle special case with pause key sending control first */ - if (is_spe) - { - if (down) - { - g_pause_spe = 1; - /* leave x_scancode 0 here, we don't want the control key down */ - } - } - else - { - x_scancode = is_ext ? 109 : 37; - g_ctrl_down = down ? x_scancode : 0; - rdpEnqueueKey(type, x_scancode); - } - break; + case 15: /* tab */ - case 69: /* Pause or Num Lock */ - if (g_pause_spe) - { - x_scancode = 110; - if (!down) - { - g_pause_spe = 0; - } - } - else - { - x_scancode = g_ctrl_down ? 110 : 77; - } - sendDownUpKeyEvent(type, x_scancode); - break; + if (!down && !g_tab_down) + { + check_keysa(); /* leave x_scancode 0 here, we don't want the tab key up */ + } + else + { + sendDownUpKeyEvent(type, 23); + } - case 28: /* Enter or Return */ - x_scancode = is_ext ? 108 : 36; - sendDownUpKeyEvent(type, x_scancode); - break; + g_tab_down = down; + break; - case 53: /* / */ - x_scancode = is_ext ? 112 : 61; - sendDownUpKeyEvent(type, x_scancode); - break; + case 29: /* left or right ctrl */ - case 55: /* * on KP or Print Screen */ - x_scancode = is_ext ? 111 : 63; - sendDownUpKeyEvent(type, x_scancode); - break; + /* this is to handle special case with pause key sending control first */ + if (is_spe) + { + if (down) + { + g_pause_spe = 1; + /* leave x_scancode 0 here, we don't want the control key down */ + } + } + else + { + x_scancode = is_ext ? 109 : 37; + g_ctrl_down = down ? x_scancode : 0; + rdpEnqueueKey(type, x_scancode); + } - case 71: /* 7 or Home */ - x_scancode = is_ext ? 97 : 79; - sendDownUpKeyEvent(type, x_scancode); - break; + break; - case 72: /* 8 or Up */ - x_scancode = is_ext ? 98 : 80; - sendDownUpKeyEvent(type, x_scancode); - break; + case 69: /* Pause or Num Lock */ - case 73: /* 9 or PgUp */ - x_scancode = is_ext ? 99 : 81; - sendDownUpKeyEvent(type, x_scancode); - break; + if (g_pause_spe) + { + x_scancode = 110; - case 75: /* 4 or Left */ - x_scancode = is_ext ? 100 : 83; - sendDownUpKeyEvent(type, x_scancode); - break; + if (!down) + { + g_pause_spe = 0; + } + } + else + { + x_scancode = g_ctrl_down ? 110 : 77; + } - case 77: /* 6 or Right */ - x_scancode = is_ext ? 102 : 85; - sendDownUpKeyEvent(type, x_scancode); - break; + sendDownUpKeyEvent(type, x_scancode); + break; - case 79: /* 1 or End */ - x_scancode = is_ext ? 103 : 87; - sendDownUpKeyEvent(type, x_scancode); - break; + case 28: /* Enter or Return */ + x_scancode = is_ext ? 108 : 36; + sendDownUpKeyEvent(type, x_scancode); + break; - case 80: /* 2 or Down */ - x_scancode = is_ext ? 104 : 88; - sendDownUpKeyEvent(type, x_scancode); - break; + case 53: /* / */ + x_scancode = is_ext ? 112 : 61; + sendDownUpKeyEvent(type, x_scancode); + break; - case 81: /* 3 or PgDn */ - x_scancode = is_ext ? 105 : 89; - sendDownUpKeyEvent(type, x_scancode); - break; + case 55: /* * on KP or Print Screen */ + x_scancode = is_ext ? 111 : 63; + sendDownUpKeyEvent(type, x_scancode); + break; - case 82: /* 0 or Insert */ - x_scancode = is_ext ? 106 : 90; - sendDownUpKeyEvent(type, x_scancode); - break; + case 71: /* 7 or Home */ + x_scancode = is_ext ? 97 : 79; + sendDownUpKeyEvent(type, x_scancode); + break; - case 83: /* . or Delete */ - x_scancode = is_ext ? 107 : 91; - sendDownUpKeyEvent(type, x_scancode); - break; + case 72: /* 8 or Up */ + x_scancode = is_ext ? 98 : 80; + sendDownUpKeyEvent(type, x_scancode); + break; - case 91: /* left win key */ - rdpEnqueueKey(type, 115); - break; + case 73: /* 9 or PgUp */ + x_scancode = is_ext ? 99 : 81; + sendDownUpKeyEvent(type, x_scancode); + break; - case 92: /* right win key */ - rdpEnqueueKey(type, 116); - break; + case 75: /* 4 or Left */ + x_scancode = is_ext ? 100 : 83; + sendDownUpKeyEvent(type, x_scancode); + break; - case 93: /* menu key */ - rdpEnqueueKey(type, 117); - break; + case 77: /* 6 or Right */ + x_scancode = is_ext ? 102 : 85; + sendDownUpKeyEvent(type, x_scancode); + break; - default: - x_scancode = rdp_scancode + MIN_KEY_CODE; - if (x_scancode > 0) - { - sendDownUpKeyEvent(type, x_scancode); - } - break; - } + case 79: /* 1 or End */ + x_scancode = is_ext ? 103 : 87; + sendDownUpKeyEvent(type, x_scancode); + break; + + case 80: /* 2 or Down */ + x_scancode = is_ext ? 104 : 88; + sendDownUpKeyEvent(type, x_scancode); + break; + + case 81: /* 3 or PgDn */ + x_scancode = is_ext ? 105 : 89; + sendDownUpKeyEvent(type, x_scancode); + break; + + case 82: /* 0 or Insert */ + x_scancode = is_ext ? 106 : 90; + sendDownUpKeyEvent(type, x_scancode); + break; + + case 83: /* . or Delete */ + x_scancode = is_ext ? 107 : 91; + sendDownUpKeyEvent(type, x_scancode); + break; + + case 91: /* left win key */ + rdpEnqueueKey(type, 115); + break; + + case 92: /* right win key */ + rdpEnqueueKey(type, 116); + break; + + case 93: /* menu key */ + rdpEnqueueKey(type, 117); + break; + + default: + x_scancode = rdp_scancode + MIN_KEY_CODE; + + if (x_scancode > 0) + { + sendDownUpKeyEvent(type, x_scancode); + } + + break; + } } /******************************************************************************/ @@ -997,26 +1044,28 @@ KbdAddEvent(int down, int param1, int param2, int param3, int param4) void KbdSync(int param1) { - int xkb_state; + int xkb_state; - xkb_state = XkbStateFieldFromRec(&(g_keyboard->key->xkbInfo->state)); - if ((!(xkb_state & 0x02)) != (!(param1 & 4))) /* caps lock */ - { - ErrorF("KbdSync: toggling caps lock\n"); - KbdAddEvent(1, 58, 0, 58, 0); - KbdAddEvent(0, 58, 49152, 58, 49152); - } + xkb_state = XkbStateFieldFromRec(&(g_keyboard->key->xkbInfo->state)); - if ((!(xkb_state & 0x10)) != (!(param1 & 2))) /* num lock */ - { - ErrorF("KbdSync: toggling num lock\n"); - KbdAddEvent(1, 69, 0, 69, 0); - KbdAddEvent(0, 69, 49152, 69, 49152); - } - if ((!(g_scroll_lock_down)) != (!(param1 & 1))) /* scroll lock */ - { - ErrorF("KbdSync: toggling scroll lock\n"); - KbdAddEvent(1, 70, 0, 70, 0); - KbdAddEvent(0, 70, 49152, 70, 49152); - } + if ((!(xkb_state & 0x02)) != (!(param1 & 4))) /* caps lock */ + { + ErrorF("KbdSync: toggling caps lock\n"); + KbdAddEvent(1, 58, 0, 58, 0); + KbdAddEvent(0, 58, 49152, 58, 49152); + } + + if ((!(xkb_state & 0x10)) != (!(param1 & 2))) /* num lock */ + { + ErrorF("KbdSync: toggling num lock\n"); + KbdAddEvent(1, 69, 0, 69, 0); + KbdAddEvent(0, 69, 49152, 69, 49152); + } + + if ((!(g_scroll_lock_down)) != (!(param1 & 1))) /* scroll lock */ + { + ErrorF("KbdSync: toggling scroll lock\n"); + KbdAddEvent(1, 70, 0, 70, 0); + KbdAddEvent(0, 70, 49152, 70, 49152); + } } diff --git a/xorg/X11R7.6/rdp/rdpmain.c b/xorg/X11R7.6/rdp/rdpmain.c index 48f5a2e9..6a88b0e0 100644 --- a/xorg/X11R7.6/rdp/rdpmain.c +++ b/xorg/X11R7.6/rdp/rdpmain.c @@ -69,33 +69,33 @@ static int g_initOutputCalled = 0; /* Common pixmap formats */ static PixmapFormatRec g_formats[MAXFORMATS] = { - { 1, 1, BITMAP_SCANLINE_PAD }, - { 4, 8, BITMAP_SCANLINE_PAD }, - { 8, 8, BITMAP_SCANLINE_PAD }, - { 15, 16, BITMAP_SCANLINE_PAD }, - { 16, 16, BITMAP_SCANLINE_PAD }, - { 24, 32, BITMAP_SCANLINE_PAD }, - { 32, 32, BITMAP_SCANLINE_PAD }, + { 1, 1, BITMAP_SCANLINE_PAD }, + { 4, 8, BITMAP_SCANLINE_PAD }, + { 8, 8, BITMAP_SCANLINE_PAD }, + { 15, 16, BITMAP_SCANLINE_PAD }, + { 16, 16, BITMAP_SCANLINE_PAD }, + { 24, 32, BITMAP_SCANLINE_PAD }, + { 32, 32, BITMAP_SCANLINE_PAD }, }; static int g_numFormats = 7; static miPointerSpriteFuncRec g_rdpSpritePointerFuncs = { - /* these are in rdpinput.c */ - rdpSpriteRealizeCursor, - rdpSpriteUnrealizeCursor, - rdpSpriteSetCursor, - rdpSpriteMoveCursor, - rdpSpriteDeviceCursorInitialize, - rdpSpriteDeviceCursorCleanup + /* these are in rdpinput.c */ + rdpSpriteRealizeCursor, + rdpSpriteUnrealizeCursor, + rdpSpriteSetCursor, + rdpSpriteMoveCursor, + rdpSpriteDeviceCursorInitialize, + rdpSpriteDeviceCursorCleanup }; static miPointerScreenFuncRec g_rdpPointerCursorFuncs = { - /* these are in rdpinput.c */ - rdpCursorOffScreen, - rdpCrossScreen, - rdpPointerWarpCursor, - rdpPointerEnqueueEvent, - rdpPointerNewEventScreen + /* these are in rdpinput.c */ + rdpCursorOffScreen, + rdpCrossScreen, + rdpPointerWarpCursor, + rdpPointerEnqueueEvent, + rdpPointerNewEventScreen }; /******************************************************************************/ @@ -103,55 +103,57 @@ static miPointerScreenFuncRec g_rdpPointerCursorFuncs = static int set_bpp(int bpp) { - int rv; + int rv; - rv = 0; - g_bpp = bpp; - if (g_bpp == 8) - { - g_Bpp = 1; - g_Bpp_mask = 0xff; - g_redBits = 3; - g_greenBits = 3; - g_blueBits = 2; - } - else if (g_bpp == 15) - { - g_Bpp = 2; - g_Bpp_mask = 0x7fff; - g_redBits = 5; - g_greenBits = 5; - g_blueBits = 5; - } - else if (g_bpp == 16) - { - g_Bpp = 2; - g_Bpp_mask = 0xffff; - g_redBits = 5; - g_greenBits = 6; - g_blueBits = 5; - } - else if (g_bpp == 24) - { - g_Bpp = 4; - g_Bpp_mask = 0xffffff; - g_redBits = 8; - g_greenBits = 8; - g_blueBits = 8; - } - else if (g_bpp == 32) - { - g_Bpp = 4; - g_Bpp_mask = 0xffffff; - g_redBits = 8; - g_greenBits = 8; - g_blueBits = 8; - } - else - { - rv = 1; - } - return rv; + rv = 0; + g_bpp = bpp; + + if (g_bpp == 8) + { + g_Bpp = 1; + g_Bpp_mask = 0xff; + g_redBits = 3; + g_greenBits = 3; + g_blueBits = 2; + } + else if (g_bpp == 15) + { + g_Bpp = 2; + g_Bpp_mask = 0x7fff; + g_redBits = 5; + g_greenBits = 5; + g_blueBits = 5; + } + else if (g_bpp == 16) + { + g_Bpp = 2; + g_Bpp_mask = 0xffff; + g_redBits = 5; + g_greenBits = 6; + g_blueBits = 5; + } + else if (g_bpp == 24) + { + g_Bpp = 4; + g_Bpp_mask = 0xffffff; + g_redBits = 8; + g_greenBits = 8; + g_blueBits = 8; + } + else if (g_bpp == 32) + { + g_Bpp = 4; + g_Bpp_mask = 0xffffff; + g_redBits = 8; + g_greenBits = 8; + g_blueBits = 8; + } + else + { + rv = 1; + } + + return rv; } /******************************************************************************/ @@ -159,9 +161,9 @@ static void rdpWakeupHandler(int i, pointer blockData, unsigned long err, pointer pReadmask) { - g_pScreen->WakeupHandler = g_rdpScreen.WakeupHandler; - g_pScreen->WakeupHandler(i, blockData, err, pReadmask); - g_pScreen->WakeupHandler = rdpWakeupHandler; + g_pScreen->WakeupHandler = g_rdpScreen.WakeupHandler; + g_pScreen->WakeupHandler(i, blockData, err, pReadmask); + g_pScreen->WakeupHandler = rdpWakeupHandler; } /******************************************************************************/ @@ -174,7 +176,7 @@ rdpBlockHandler1(pointer blockData, OSTimePtr pTimeout, pointer pReadmask) static void rdpWakeupHandler1(pointer blockData, int result, pointer pReadmask) { - rdpup_check(); + rdpup_check(); } #if 0 @@ -182,15 +184,15 @@ rdpWakeupHandler1(pointer blockData, int result, pointer pReadmask) static Bool rdpDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) { - ErrorF("rdpDeviceCursorInitializeProcPtr:\n"); - return 1; + ErrorF("rdpDeviceCursorInitializeProcPtr:\n"); + return 1; } /******************************************************************************/ static void rdpDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) { - ErrorF("rdpDeviceCursorCleanupProcPtr:\n"); + ErrorF("rdpDeviceCursorCleanupProcPtr:\n"); } #endif @@ -199,301 +201,327 @@ rdpDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) Bool rdpCreateColormap(ColormapPtr pCmap) { - ErrorF("rdpCreateColormap:\n"); - return 1; + ErrorF("rdpCreateColormap:\n"); + return 1; } /******************************************************************************/ static void rdpDestroyColormap(ColormapPtr pColormap) { - ErrorF("rdpDestroyColormap:\n"); + ErrorF("rdpDestroyColormap:\n"); } #endif /******************************************************************************/ /* returns boolean, true if everything is ok */ static Bool -rdpScreenInit(int index, ScreenPtr pScreen, int argc, char** argv) +rdpScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) { - int dpix; - int dpiy; - int ret; - Bool vis_found; - VisualPtr vis; - PictureScreenPtr ps; - rrScrPrivPtr pRRScrPriv; + int dpix; + int dpiy; + int ret; + Bool vis_found; + VisualPtr vis; + PictureScreenPtr ps; + rrScrPrivPtr pRRScrPriv; - g_pScreen = pScreen; + g_pScreen = pScreen; - /*dpix = 75; - dpiy = 75;*/ - dpix = PixelDPI; - dpiy = PixelDPI; - if (monitorResolution != 0) - { - dpix = monitorResolution; - dpiy = monitorResolution; - } - g_rdpScreen.paddedWidthInBytes = PixmapBytePad(g_rdpScreen.width, - g_rdpScreen.depth); - g_rdpScreen.bitsPerPixel = rdpBitsPerPixel(g_rdpScreen.depth); - ErrorF("\n"); - ErrorF("X11rdp, an X server for xrdp\n"); - ErrorF("Version %s\n", X11RDPVER); - ErrorF("Copyright (C) 2005-2012 Jay Sorg\n"); - ErrorF("See http://xrdp.sf.net for information on xrdp.\n"); + /*dpix = 75; + dpiy = 75;*/ + dpix = PixelDPI; + dpiy = PixelDPI; + + if (monitorResolution != 0) + { + dpix = monitorResolution; + dpiy = monitorResolution; + } + + g_rdpScreen.paddedWidthInBytes = PixmapBytePad(g_rdpScreen.width, + g_rdpScreen.depth); + g_rdpScreen.bitsPerPixel = rdpBitsPerPixel(g_rdpScreen.depth); + ErrorF("\n"); + ErrorF("X11rdp, an X server for xrdp\n"); + ErrorF("Version %s\n", X11RDPVER); + ErrorF("Copyright (C) 2005-2012 Jay Sorg\n"); + ErrorF("See http://xrdp.sf.net for information on xrdp.\n"); #if defined(XORG_VERSION_CURRENT) && defined (XVENDORNAME) - ErrorF("Underlying X server release %d, %s\n", - XORG_VERSION_CURRENT, XVENDORNAME); + ErrorF("Underlying X server release %d, %s\n", + XORG_VERSION_CURRENT, XVENDORNAME); #endif #if defined(XORG_RELEASE) - ErrorF("Xorg %s\n", XORG_RELEASE); + ErrorF("Xorg %s\n", XORG_RELEASE); #endif - ErrorF("Screen width %d height %d depth %d bpp %d\n", g_rdpScreen.width, - g_rdpScreen.height, g_rdpScreen.depth, g_rdpScreen.bitsPerPixel); - ErrorF("dpix %d dpiy %d\n", dpix, dpiy); - if (g_rdpScreen.pfbMemory == 0) - { - g_rdpScreen.sizeInBytes = - (g_rdpScreen.paddedWidthInBytes * g_rdpScreen.height); - ErrorF("buffer size %d\n", g_rdpScreen.sizeInBytes); - g_rdpScreen.pfbMemory = (char*)g_malloc(2048 * 2048 * 4, 1); - } - if (g_rdpScreen.pfbMemory == 0) - { - rdpLog("rdpScreenInit g_malloc failed\n"); - return 0; - } - miClearVisualTypes(); - if (defaultColorVisualClass == -1) - { - defaultColorVisualClass = TrueColor; - } - if (!miSetVisualTypes(g_rdpScreen.depth, - miGetDefaultVisualMask(g_rdpScreen.depth), - 8, defaultColorVisualClass)) - { - rdpLog("rdpScreenInit miSetVisualTypes failed\n"); - return 0; - } - miSetPixmapDepths(); - switch (g_rdpScreen.bitsPerPixel) - { - case 8: - ret = fbScreenInit(pScreen, g_rdpScreen.pfbMemory, - g_rdpScreen.width, g_rdpScreen.height, - dpix, dpiy, g_rdpScreen.paddedWidthInBytes, 8); - break; - case 16: - ret = fbScreenInit(pScreen, g_rdpScreen.pfbMemory, - g_rdpScreen.width, g_rdpScreen.height, - dpix, dpiy, g_rdpScreen.paddedWidthInBytes / 2, 16); - break; - case 32: - ret = fbScreenInit(pScreen, g_rdpScreen.pfbMemory, - g_rdpScreen.width, g_rdpScreen.height, - dpix, dpiy, g_rdpScreen.paddedWidthInBytes / 4, 32); - break; - default: - ErrorF("rdpScreenInit: error\n"); - return 0; - } - if (!ret) - { - ErrorF("rdpScreenInit: error\n"); - return 0; - } + ErrorF("Screen width %d height %d depth %d bpp %d\n", g_rdpScreen.width, + g_rdpScreen.height, g_rdpScreen.depth, g_rdpScreen.bitsPerPixel); + ErrorF("dpix %d dpiy %d\n", dpix, dpiy); - miInitializeBackingStore(pScreen); - - /* this is for rgb, not bgr, just doing rgb for now */ - vis = g_pScreen->visuals + (g_pScreen->numVisuals - 1); - while (vis >= pScreen->visuals) - { - if ((vis->class | DynamicClass) == DirectColor) + if (g_rdpScreen.pfbMemory == 0) { - vis->offsetBlue = 0; - vis->blueMask = (1 << g_blueBits) - 1; - vis->offsetGreen = g_blueBits; - vis->greenMask = ((1 << g_greenBits) - 1) << vis->offsetGreen; - vis->offsetRed = g_blueBits + g_greenBits; - vis->redMask = ((1 << g_redBits) - 1) << vis->offsetRed; + g_rdpScreen.sizeInBytes = + (g_rdpScreen.paddedWidthInBytes * g_rdpScreen.height); + ErrorF("buffer size %d\n", g_rdpScreen.sizeInBytes); + g_rdpScreen.pfbMemory = (char *)g_malloc(2048 * 2048 * 4, 1); } - vis--; - } - if (g_rdpScreen.bitsPerPixel > 4) - { - fbPictureInit(pScreen, 0, 0); - } + if (g_rdpScreen.pfbMemory == 0) + { + rdpLog("rdpScreenInit g_malloc failed\n"); + return 0; + } - if (!dixRegisterPrivateKey(&g_rdpGCIndex, PRIVATE_GC, sizeof(rdpGCRec))) - { - FatalError("rdpScreenInit: dixRegisterPrivateKey PRIVATE_GC failed\n"); - } + miClearVisualTypes(); - if (!dixRegisterPrivateKey(&g_rdpWindowIndex, PRIVATE_WINDOW, sizeof(rdpWindowRec))) - { - FatalError("rdpScreenInit: dixRegisterPrivateKey PRIVATE_WINDOW failed\n"); - } + if (defaultColorVisualClass == -1) + { + defaultColorVisualClass = TrueColor; + } - if (!dixRegisterPrivateKey(&g_rdpPixmapIndex, PRIVATE_PIXMAP, sizeof(rdpPixmapRec))) - { - FatalError("rdpScreenInit: dixRegisterPrivateKey PRIVATE_PIXMAP failed\n"); - } + if (!miSetVisualTypes(g_rdpScreen.depth, + miGetDefaultVisualMask(g_rdpScreen.depth), + 8, defaultColorVisualClass)) + { + rdpLog("rdpScreenInit miSetVisualTypes failed\n"); + return 0; + } - /* Random screen procedures */ - g_rdpScreen.CloseScreen = pScreen->CloseScreen; - /* GC procedures */ - g_rdpScreen.CreateGC = pScreen->CreateGC; - /* Pixmap procudures */ - g_rdpScreen.CreatePixmap = pScreen->CreatePixmap; - g_rdpScreen.DestroyPixmap = pScreen->DestroyPixmap; + miSetPixmapDepths(); - /* Window Procedures */ - g_rdpScreen.CreateWindow = pScreen->CreateWindow; - g_rdpScreen.DestroyWindow = pScreen->DestroyWindow; - g_rdpScreen.ChangeWindowAttributes = pScreen->ChangeWindowAttributes; - g_rdpScreen.RealizeWindow = pScreen->RealizeWindow; - g_rdpScreen.UnrealizeWindow = pScreen->UnrealizeWindow; - g_rdpScreen.PositionWindow = pScreen->PositionWindow; - g_rdpScreen.WindowExposures = pScreen->WindowExposures; - g_rdpScreen.CopyWindow = pScreen->CopyWindow; - g_rdpScreen.ClearToBackground = pScreen->ClearToBackground; + switch (g_rdpScreen.bitsPerPixel) + { + case 8: + ret = fbScreenInit(pScreen, g_rdpScreen.pfbMemory, + g_rdpScreen.width, g_rdpScreen.height, + dpix, dpiy, g_rdpScreen.paddedWidthInBytes, 8); + break; + case 16: + ret = fbScreenInit(pScreen, g_rdpScreen.pfbMemory, + g_rdpScreen.width, g_rdpScreen.height, + dpix, dpiy, g_rdpScreen.paddedWidthInBytes / 2, 16); + break; + case 32: + ret = fbScreenInit(pScreen, g_rdpScreen.pfbMemory, + g_rdpScreen.width, g_rdpScreen.height, + dpix, dpiy, g_rdpScreen.paddedWidthInBytes / 4, 32); + break; + default: + ErrorF("rdpScreenInit: error\n"); + return 0; + } - /* Backing store procedures */ - g_rdpScreen.RestoreAreas = pScreen->RestoreAreas; - g_rdpScreen.WakeupHandler = pScreen->WakeupHandler; + if (!ret) + { + ErrorF("rdpScreenInit: error\n"); + return 0; + } - g_rdpScreen.CreateColormap = pScreen->CreateColormap; - g_rdpScreen.DestroyColormap = pScreen->DestroyColormap; + miInitializeBackingStore(pScreen); - ps = GetPictureScreenIfSet(pScreen); - if (ps) - { - g_rdpScreen.Composite = ps->Composite; - g_rdpScreen.Glyphs = ps->Glyphs; + /* this is for rgb, not bgr, just doing rgb for now */ + vis = g_pScreen->visuals + (g_pScreen->numVisuals - 1); - } - pScreen->blackPixel = g_rdpScreen.blackPixel; - pScreen->whitePixel = g_rdpScreen.whitePixel; - /* Random screen procedures */ - pScreen->CloseScreen = rdpCloseScreen; - pScreen->WakeupHandler = rdpWakeupHandler; - if (ps) - { - ps->Composite = rdpComposite; - ps->Glyphs = rdpGlyphs; - } - pScreen->SaveScreen = rdpSaveScreen; - /* GC procedures */ - pScreen->CreateGC = rdpCreateGC; + while (vis >= pScreen->visuals) + { + if ((vis->class | DynamicClass) == DirectColor) + { + vis->offsetBlue = 0; + vis->blueMask = (1 << g_blueBits) - 1; + vis->offsetGreen = g_blueBits; + vis->greenMask = ((1 << g_greenBits) - 1) << vis->offsetGreen; + vis->offsetRed = g_blueBits + g_greenBits; + vis->redMask = ((1 << g_redBits) - 1) << vis->offsetRed; + } - if (g_wrapPixmap) - { - /* Pixmap procedures */ - pScreen->CreatePixmap = rdpCreatePixmap; - pScreen->DestroyPixmap = rdpDestroyPixmap; - } + vis--; + } + + if (g_rdpScreen.bitsPerPixel > 4) + { + fbPictureInit(pScreen, 0, 0); + } + + if (!dixRegisterPrivateKey(&g_rdpGCIndex, PRIVATE_GC, sizeof(rdpGCRec))) + { + FatalError("rdpScreenInit: dixRegisterPrivateKey PRIVATE_GC failed\n"); + } + + if (!dixRegisterPrivateKey(&g_rdpWindowIndex, PRIVATE_WINDOW, sizeof(rdpWindowRec))) + { + FatalError("rdpScreenInit: dixRegisterPrivateKey PRIVATE_WINDOW failed\n"); + } + + if (!dixRegisterPrivateKey(&g_rdpPixmapIndex, PRIVATE_PIXMAP, sizeof(rdpPixmapRec))) + { + FatalError("rdpScreenInit: dixRegisterPrivateKey PRIVATE_PIXMAP failed\n"); + } + + /* Random screen procedures */ + g_rdpScreen.CloseScreen = pScreen->CloseScreen; + /* GC procedures */ + g_rdpScreen.CreateGC = pScreen->CreateGC; + /* Pixmap procudures */ + g_rdpScreen.CreatePixmap = pScreen->CreatePixmap; + g_rdpScreen.DestroyPixmap = pScreen->DestroyPixmap; - if (g_wrapWindow) - { /* Window Procedures */ - pScreen->CreateWindow = rdpCreateWindow; - pScreen->DestroyWindow = rdpDestroyWindow; - pScreen->ChangeWindowAttributes = rdpChangeWindowAttributes; - pScreen->RealizeWindow = rdpRealizeWindow; - pScreen->UnrealizeWindow = rdpUnrealizeWindow; - pScreen->PositionWindow = rdpPositionWindow; - pScreen->WindowExposures = rdpWindowExposures; - } + g_rdpScreen.CreateWindow = pScreen->CreateWindow; + g_rdpScreen.DestroyWindow = pScreen->DestroyWindow; + g_rdpScreen.ChangeWindowAttributes = pScreen->ChangeWindowAttributes; + g_rdpScreen.RealizeWindow = pScreen->RealizeWindow; + g_rdpScreen.UnrealizeWindow = pScreen->UnrealizeWindow; + g_rdpScreen.PositionWindow = pScreen->PositionWindow; + g_rdpScreen.WindowExposures = pScreen->WindowExposures; + g_rdpScreen.CopyWindow = pScreen->CopyWindow; + g_rdpScreen.ClearToBackground = pScreen->ClearToBackground; - pScreen->CopyWindow = rdpCopyWindow; - pScreen->ClearToBackground = rdpClearToBackground; + /* Backing store procedures */ + g_rdpScreen.RestoreAreas = pScreen->RestoreAreas; + g_rdpScreen.WakeupHandler = pScreen->WakeupHandler; - /* Backing store procedures */ - pScreen->RestoreAreas = rdpRestoreAreas; + g_rdpScreen.CreateColormap = pScreen->CreateColormap; + g_rdpScreen.DestroyColormap = pScreen->DestroyColormap; + + ps = GetPictureScreenIfSet(pScreen); + + if (ps) + { + g_rdpScreen.Composite = ps->Composite; + g_rdpScreen.Glyphs = ps->Glyphs; + + } + + pScreen->blackPixel = g_rdpScreen.blackPixel; + pScreen->whitePixel = g_rdpScreen.whitePixel; + /* Random screen procedures */ + pScreen->CloseScreen = rdpCloseScreen; + pScreen->WakeupHandler = rdpWakeupHandler; + + if (ps) + { + ps->Composite = rdpComposite; + ps->Glyphs = rdpGlyphs; + } + + pScreen->SaveScreen = rdpSaveScreen; + /* GC procedures */ + pScreen->CreateGC = rdpCreateGC; + + if (g_wrapPixmap) + { + /* Pixmap procedures */ + pScreen->CreatePixmap = rdpCreatePixmap; + pScreen->DestroyPixmap = rdpDestroyPixmap; + } + + if (g_wrapWindow) + { + /* Window Procedures */ + pScreen->CreateWindow = rdpCreateWindow; + pScreen->DestroyWindow = rdpDestroyWindow; + pScreen->ChangeWindowAttributes = rdpChangeWindowAttributes; + pScreen->RealizeWindow = rdpRealizeWindow; + pScreen->UnrealizeWindow = rdpUnrealizeWindow; + pScreen->PositionWindow = rdpPositionWindow; + pScreen->WindowExposures = rdpWindowExposures; + } + + pScreen->CopyWindow = rdpCopyWindow; + pScreen->ClearToBackground = rdpClearToBackground; + + /* Backing store procedures */ + pScreen->RestoreAreas = rdpRestoreAreas; #if 0 - pScreen->CreateColormap = rdpCreateColormap; - pScreen->DestroyColormap = rdpDestroyColormap; + pScreen->CreateColormap = rdpCreateColormap; + pScreen->DestroyColormap = rdpDestroyColormap; #endif - miPointerInitialize(pScreen, &g_rdpSpritePointerFuncs, - &g_rdpPointerCursorFuncs, 1); + miPointerInitialize(pScreen, &g_rdpSpritePointerFuncs, + &g_rdpPointerCursorFuncs, 1); #if 0 - pScreen->DeviceCursorInitialize = rdpDeviceCursorInitialize; - pScreen->DeviceCursorCleanup = rdpDeviceCursorCleanup; + pScreen->DeviceCursorInitialize = rdpDeviceCursorInitialize; + pScreen->DeviceCursorCleanup = rdpDeviceCursorCleanup; #endif - vis_found = 0; - vis = g_pScreen->visuals + (g_pScreen->numVisuals - 1); - while (vis >= pScreen->visuals) - { - if (vis->vid == pScreen->rootVisual) + vis_found = 0; + vis = g_pScreen->visuals + (g_pScreen->numVisuals - 1); + + while (vis >= pScreen->visuals) { - vis_found = 1; + if (vis->vid == pScreen->rootVisual) + { + vis_found = 1; + } + + vis--; } - vis--; - } - if (!vis_found) - { - rdpLog("rdpScreenInit: couldn't find root visual\n"); - exit(1); - } - ret = 1; - if (ret) - { - ret = fbCreateDefColormap(pScreen); - if (!ret) + + if (!vis_found) { - ErrorF("rdpScreenInit: fbCreateDefColormap failed\n"); + rdpLog("rdpScreenInit: couldn't find root visual\n"); + exit(1); } - } - if (ret) - { - ret = rdpup_init(); - if (!ret) + + ret = 1; + + if (ret) { - ErrorF("rdpScreenInit: rdpup_init failed\n"); + ret = fbCreateDefColormap(pScreen); + + if (!ret) + { + ErrorF("rdpScreenInit: fbCreateDefColormap failed\n"); + } } - } - if (ret) - { - RegisterBlockAndWakeupHandlers(rdpBlockHandler1, rdpWakeupHandler1, NULL); - } - if (!RRScreenInit(pScreen)) - { - ErrorF("rdpmain.c: RRScreenInit: screen init failed\n"); - } - else - { - pRRScrPriv = rrGetScrPriv(pScreen); - ErrorF("pRRScrPriv %p\n", pRRScrPriv); - pRRScrPriv->rrSetConfig = rdpRRSetConfig; + if (ret) + { + ret = rdpup_init(); - pRRScrPriv->rrGetInfo = rdpRRGetInfo; + if (!ret) + { + ErrorF("rdpScreenInit: rdpup_init failed\n"); + } + } - pRRScrPriv->rrScreenSetSize = rdpRRScreenSetSize; - pRRScrPriv->rrCrtcSet = rdpRRCrtcSet; - pRRScrPriv->rrCrtcGetGamma = rdpRRCrtcGetGamma; - pRRScrPriv->rrCrtcSetGamma = rdpRRCrtcSetGamma; - pRRScrPriv->rrOutputSetProperty = rdpRROutputSetProperty; - pRRScrPriv->rrOutputValidateMode = rdpRROutputValidateMode; - pRRScrPriv->rrModeDestroy = rdpRRModeDestroy; + if (ret) + { + RegisterBlockAndWakeupHandlers(rdpBlockHandler1, rdpWakeupHandler1, NULL); + } - pRRScrPriv->rrOutputGetProperty = rdpRROutputGetProperty; - pRRScrPriv->rrGetPanning = rdpRRGetPanning; - pRRScrPriv->rrSetPanning = rdpRRSetPanning; + if (!RRScreenInit(pScreen)) + { + ErrorF("rdpmain.c: RRScreenInit: screen init failed\n"); + } + else + { + pRRScrPriv = rrGetScrPriv(pScreen); + ErrorF("pRRScrPriv %p\n", pRRScrPriv); - } + pRRScrPriv->rrSetConfig = rdpRRSetConfig; - ErrorF("rdpScreenInit: ret %d\n", ret); + pRRScrPriv->rrGetInfo = rdpRRGetInfo; - return ret; + pRRScrPriv->rrScreenSetSize = rdpRRScreenSetSize; + pRRScrPriv->rrCrtcSet = rdpRRCrtcSet; + pRRScrPriv->rrCrtcGetGamma = rdpRRCrtcGetGamma; + pRRScrPriv->rrCrtcSetGamma = rdpRRCrtcSetGamma; + pRRScrPriv->rrOutputSetProperty = rdpRROutputSetProperty; + pRRScrPriv->rrOutputValidateMode = rdpRROutputValidateMode; + pRRScrPriv->rrModeDestroy = rdpRRModeDestroy; + + pRRScrPriv->rrOutputGetProperty = rdpRROutputGetProperty; + pRRScrPriv->rrGetPanning = rdpRRGetPanning; + pRRScrPriv->rrSetPanning = rdpRRSetPanning; + + } + + ErrorF("rdpScreenInit: ret %d\n", ret); + + return ret; } /******************************************************************************/ @@ -501,52 +529,61 @@ rdpScreenInit(int index, ScreenPtr pScreen, int argc, char** argv) returns the number or parameters processed if it dosen't apply to the rdp part, return 0 */ int -ddxProcessArgument(int argc, char** argv, int i) +ddxProcessArgument(int argc, char **argv, int i) { - if (g_firstTime) - { - memset(&g_rdpScreen, 0, sizeof(g_rdpScreen)); - g_rdpScreen.width = 1024; - g_rdpScreen.height = 768; - g_rdpScreen.depth = 24; - set_bpp(24); - g_rdpScreen.blackPixel = 1; - g_firstTime = 0; - RRExtensionInit(); - } - if (strcmp(argv[i], "-geometry") == 0) - { - if (i + 1 >= argc) + if (g_firstTime) { - UseMsg(); + memset(&g_rdpScreen, 0, sizeof(g_rdpScreen)); + g_rdpScreen.width = 1024; + g_rdpScreen.height = 768; + g_rdpScreen.depth = 24; + set_bpp(24); + g_rdpScreen.blackPixel = 1; + g_firstTime = 0; + RRExtensionInit(); } - if (sscanf(argv[i + 1], "%dx%d", &g_rdpScreen.width, - &g_rdpScreen.height) != 2) + + if (strcmp(argv[i], "-geometry") == 0) { - ErrorF("Invalid geometry %s\n", argv[i + 1]); - UseMsg(); + if (i + 1 >= argc) + { + UseMsg(); + } + + if (sscanf(argv[i + 1], "%dx%d", &g_rdpScreen.width, + &g_rdpScreen.height) != 2) + { + ErrorF("Invalid geometry %s\n", argv[i + 1]); + UseMsg(); + } + + return 2; } - return 2; - } - if (strcmp(argv[i], "-depth") == 0) - { - if (i + 1 >= argc) + + if (strcmp(argv[i], "-depth") == 0) { - UseMsg(); + if (i + 1 >= argc) + { + UseMsg(); + } + + g_rdpScreen.depth = atoi(argv[i + 1]); + + if (set_bpp(g_rdpScreen.depth) != 0) + { + UseMsg(); + } + + return 2; } - g_rdpScreen.depth = atoi(argv[i + 1]); - if (set_bpp(g_rdpScreen.depth) != 0) + + if (strcmp(argv[i], "-uds") == 0) { - UseMsg(); + g_use_uds = 1; + return 1; } - return 2; - } - if (strcmp(argv[i], "-uds") == 0) - { - g_use_uds = 1; - return 1; - } - return 0; + + return 0; } /******************************************************************************/ @@ -564,27 +601,27 @@ ddxInitGlobals(void) /******************************************************************************/ int -XkbDDXSwitchScreen(DeviceIntPtr dev, KeyCode key, XkbAction* act) +XkbDDXSwitchScreen(DeviceIntPtr dev, KeyCode key, XkbAction *act) { - ErrorF("XkbDDXSwitchScreen:\n"); - return 1; + ErrorF("XkbDDXSwitchScreen:\n"); + return 1; } /******************************************************************************/ int -XkbDDXPrivate(DeviceIntPtr dev, KeyCode key, XkbAction* act) +XkbDDXPrivate(DeviceIntPtr dev, KeyCode key, XkbAction *act) { - ErrorF("XkbDDXPrivate:\n"); - return 0; + ErrorF("XkbDDXPrivate:\n"); + return 0; } /******************************************************************************/ int -XkbDDXTerminateServer(DeviceIntPtr dev, KeyCode key, XkbAction* act) +XkbDDXTerminateServer(DeviceIntPtr dev, KeyCode key, XkbAction *act) { - ErrorF("XkbDDXTerminateServer:\n"); - GiveUp(1); - return 0; + ErrorF("XkbDDXTerminateServer:\n"); + GiveUp(1); + return 0; } /******************************************************************************/ @@ -592,50 +629,55 @@ XkbDDXTerminateServer(DeviceIntPtr dev, KeyCode key, XkbAction* act) AddScreen for each screen (but we only ever have one), and in turn this will call rdpScreenInit. */ void -InitOutput(ScreenInfo* screenInfo, int argc, char** argv) +InitOutput(ScreenInfo *screenInfo, int argc, char **argv) { - int i; + int i; - ErrorF("InitOutput:\n"); - g_initOutputCalled = 1; - /* initialize pixmap formats */ - screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; - screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; - screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; - screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; - screenInfo->numPixmapFormats = g_numFormats; - for (i = 0; i < g_numFormats; i++) - { - screenInfo->formats[i] = g_formats[i]; - } - if (!AddCallback(&ClientStateCallback, rdpClientStateChange, NULL)) - { - rdpLog("InitOutput: AddCallback failed\n"); - return; - } - /* initialize screen */ - if (AddScreen(rdpScreenInit, argc, argv) == -1) - { - FatalError("Couldn't add screen\n"); - } - ErrorF("InitOutput: out\n"); + ErrorF("InitOutput:\n"); + g_initOutputCalled = 1; + /* initialize pixmap formats */ + screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; + screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; + screenInfo->numPixmapFormats = g_numFormats; + + for (i = 0; i < g_numFormats; i++) + { + screenInfo->formats[i] = g_formats[i]; + } + + if (!AddCallback(&ClientStateCallback, rdpClientStateChange, NULL)) + { + rdpLog("InitOutput: AddCallback failed\n"); + return; + } + + /* initialize screen */ + if (AddScreen(rdpScreenInit, argc, argv) == -1) + { + FatalError("Couldn't add screen\n"); + } + + ErrorF("InitOutput: out\n"); } /******************************************************************************/ void -InitInput(int argc, char** argv) +InitInput(int argc, char **argv) { - int rc; + int rc; - ErrorF("InitInput:\n"); - rc = AllocDevicePair(serverClient, "X11rdp", &g_pointer, &g_keyboard, - rdpMouseProc, rdpKeybdProc, 0); - if (rc != Success) - { - FatalError("Failed to init X11rdp default devices.\n"); - } + ErrorF("InitInput:\n"); + rc = AllocDevicePair(serverClient, "X11rdp", &g_pointer, &g_keyboard, + rdpMouseProc, rdpKeybdProc, 0); - mieqInit(); + if (rc != Success) + { + FatalError("Failed to init X11rdp default devices.\n"); + } + + mieqInit(); } @@ -643,35 +685,37 @@ InitInput(int argc, char** argv) void ddxGiveUp(void) { - char unixSocketName[128]; + char unixSocketName[128]; - ErrorF("ddxGiveUp:\n"); - g_free(g_rdpScreen.pfbMemory); - if (g_initOutputCalled) - { - sprintf(unixSocketName, "/tmp/.X11-unix/X%s", display); - unlink(unixSocketName); - sprintf(unixSocketName, "/tmp/.xrdp/xrdp_disconnect_display_%s", display); - unlink(unixSocketName); - if(g_uds_data[0] != 0) + ErrorF("ddxGiveUp:\n"); + g_free(g_rdpScreen.pfbMemory); + + if (g_initOutputCalled) { - unlink(g_uds_data); + sprintf(unixSocketName, "/tmp/.X11-unix/X%s", display); + unlink(unixSocketName); + sprintf(unixSocketName, "/tmp/.xrdp/xrdp_disconnect_display_%s", display); + unlink(unixSocketName); + + if (g_uds_data[0] != 0) + { + unlink(g_uds_data); + } } - } } /******************************************************************************/ Bool LegalModifier(unsigned int key, DeviceIntPtr pDev) { - return 1; /* true */ + return 1; /* true */ } /******************************************************************************/ void ProcessInputEvents(void) { - mieqProcessInputEvents(); + mieqProcessInputEvents(); } /******************************************************************************/ @@ -686,7 +730,7 @@ rfbRootPropertyChange(PropertyPtr pProp) void AbortDDX(void) { - ddxGiveUp(); + ddxGiveUp(); } /******************************************************************************/ @@ -700,13 +744,13 @@ OsVendorFatalError(void) void ddxUseMsg(void) { - ErrorF("\n"); - ErrorF("X11rdp specific options\n"); - ErrorF("-geometry WxH set framebuffer width & height\n"); - ErrorF("-depth D set framebuffer depth\n"); - ErrorF("-uds create and listen on /tmp/.xrdp/xrdp_display_x\n"); - ErrorF("\n"); - exit(1); + ErrorF("\n"); + ErrorF("X11rdp specific options\n"); + ErrorF("-geometry WxH set framebuffer width & height\n"); + ErrorF("-depth D set framebuffer depth\n"); + ErrorF("-uds create and listen on /tmp/.xrdp/xrdp_display_x\n"); + ErrorF("\n"); + exit(1); } /******************************************************************************/ @@ -719,19 +763,19 @@ OsVendorPreInit(void) void CloseInput(void) { - ErrorF("CloseInput\n"); + ErrorF("CloseInput\n"); } /******************************************************************************/ void DDXRingBell(int volume, int pitch, int duration) { - ErrorF("DDXRingBell\n"); + ErrorF("DDXRingBell\n"); } /******************************************************************************/ void DeleteInputDeviceRequest(DeviceIntPtr dev) { - ErrorF("DeleteInputDeviceRequest\n"); + ErrorF("DeleteInputDeviceRequest\n"); } diff --git a/xorg/X11R7.6/rdp/rdpmisc.c b/xorg/X11R7.6/rdp/rdpmisc.c index d3defe27..c221dd15 100644 --- a/xorg/X11R7.6/rdp/rdpmisc.c +++ b/xorg/X11R7.6/rdp/rdpmisc.c @@ -32,60 +32,60 @@ Bool noFontCacheExtension = 1; void rdpLog(char *format, ...) { - va_list args; - char buf[256]; - time_t clock; + va_list args; + char buf[256]; + time_t clock; - va_start(args, format); - time(&clock); - strftime(buf, 255, "%d/%m/%y %T ", localtime(&clock)); - fprintf(stderr, "%s", buf); - vfprintf(stderr, format, args); - fflush(stderr); - va_end(args); + va_start(args, format); + time(&clock); + strftime(buf, 255, "%d/%m/%y %T ", localtime(&clock)); + fprintf(stderr, "%s", buf); + vfprintf(stderr, format, args); + fflush(stderr); + va_end(args); } /******************************************************************************/ int rdpBitsPerPixel(int depth) { - if (depth == 1) - { - return 1; - } - else if (depth <= 8) - { - return 8; - } - else if (depth <= 16) - { - return 16; - } - else - { - return 32; - } + if (depth == 1) + { + return 1; + } + else if (depth <= 8) + { + return 8; + } + else if (depth <= 16) + { + return 16; + } + else + { + return 32; + } } /******************************************************************************/ void -rdpClientStateChange(CallbackListPtr* cbl, pointer myData, pointer clt) +rdpClientStateChange(CallbackListPtr *cbl, pointer myData, pointer clt) { - dispatchException &= ~DE_RESET; /* hack - force server not to reset */ + dispatchException &= ~DE_RESET; /* hack - force server not to reset */ } /******************************************************************************/ int DPMSSupported(void) { - return 0; + return 0; } /******************************************************************************/ int -DPSMGet(int* level) +DPSMGet(int *level) { - return -1; + return -1; } /******************************************************************************/ @@ -102,38 +102,38 @@ AddOtherInputDevices(void) /******************************************************************************/ void -OpenInputDevice(DeviceIntPtr dev, ClientPtr client, int* status) +OpenInputDevice(DeviceIntPtr dev, ClientPtr client, int *status) { } /******************************************************************************/ int SetDeviceValuators(register ClientPtr client, DeviceIntPtr dev, - int* valuators, int first_valuator, int num_valuators) + int *valuators, int first_valuator, int num_valuators) { - return BadMatch; + return BadMatch; } /******************************************************************************/ int SetDeviceMode(register ClientPtr client, DeviceIntPtr dev, int mode) { - return BadMatch; + return BadMatch; } /******************************************************************************/ int ChangeKeyboardDevice(DeviceIntPtr old_dev, DeviceIntPtr new_dev) { - return BadMatch; + return BadMatch; } /******************************************************************************/ int ChangeDeviceControl(register ClientPtr client, DeviceIntPtr dev, - void* control) + void *control) { - return BadMatch; + return BadMatch; } /******************************************************************************/ @@ -141,7 +141,7 @@ int ChangePointerDevice(DeviceIntPtr old_dev, DeviceIntPtr new_dev, unsigned char x, unsigned char y) { - return BadMatch; + return BadMatch; } /******************************************************************************/ @@ -154,332 +154,357 @@ CloseInputDevice(DeviceIntPtr d, ClientPtr client) /*****************************************************************************/ int -g_tcp_recv(int sck, void* ptr, int len, int flags) +g_tcp_recv(int sck, void *ptr, int len, int flags) { - return recv(sck, ptr, len, flags); + return recv(sck, ptr, len, flags); } /*****************************************************************************/ void g_tcp_close(int sck) { - if (sck == 0) - { - return; - } - shutdown(sck, 2); - close(sck); + if (sck == 0) + { + return; + } + + shutdown(sck, 2); + close(sck); } /*****************************************************************************/ int g_tcp_last_error_would_block(int sck) { - return (errno == EWOULDBLOCK) || (errno == EINPROGRESS); + return (errno == EWOULDBLOCK) || (errno == EINPROGRESS); } /*****************************************************************************/ void g_sleep(int msecs) { - usleep(msecs * 1000); + usleep(msecs * 1000); } /*****************************************************************************/ int -g_tcp_send(int sck, void* ptr, int len, int flags) +g_tcp_send(int sck, void *ptr, int len, int flags) { - return send(sck, ptr, len, flags); + return send(sck, ptr, len, flags); } /*****************************************************************************/ -void* +void * g_malloc(int size, int zero) { - char* rv; + char *rv; -//#ifdef _XSERVER64 + //#ifdef _XSERVER64 #if 1 - /* I thought xalloc whould work here but I guess not, why, todo */ - rv = (char*)malloc(size); + /* I thought xalloc whould work here but I guess not, why, todo */ + rv = (char *)malloc(size); #else - rv = (char*)Xalloc(size); + rv = (char *)Xalloc(size); #endif - if (zero) - { - if (rv != 0) + + if (zero) { - memset(rv, 0, size); + if (rv != 0) + { + memset(rv, 0, size); + } } - } - return rv; + + return rv; } /*****************************************************************************/ void -g_free(void* ptr) +g_free(void *ptr) { - if (ptr != 0) - { -//#ifdef _XSERVER64 + if (ptr != 0) + { + //#ifdef _XSERVER64 #if 1 - /* I thought xfree whould work here but I guess not, why, todo */ - free(ptr); + /* I thought xfree whould work here but I guess not, why, todo */ + free(ptr); #else - Xfree(ptr); + Xfree(ptr); #endif - } + } } /*****************************************************************************/ void -g_sprintf(char* dest, char* format, ...) +g_sprintf(char *dest, char *format, ...) { - va_list ap; + va_list ap; - va_start(ap, format); - vsprintf(dest, format, ap); - va_end(ap); + va_start(ap, format); + vsprintf(dest, format, ap); + va_end(ap); } /*****************************************************************************/ int g_tcp_socket(void) { - int rv; - int i; + int rv; + int i; - i = 1; - rv = socket(PF_INET, SOCK_STREAM, 0); - setsockopt(rv, IPPROTO_TCP, TCP_NODELAY, (void*)&i, sizeof(i)); - setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (void*)&i, sizeof(i)); - return rv; + i = 1; + rv = socket(PF_INET, SOCK_STREAM, 0); + setsockopt(rv, IPPROTO_TCP, TCP_NODELAY, (void *)&i, sizeof(i)); + setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (void *)&i, sizeof(i)); + return rv; } /*****************************************************************************/ int g_tcp_local_socket_dgram(void) { - return socket(AF_UNIX, SOCK_DGRAM, 0); + return socket(AF_UNIX, SOCK_DGRAM, 0); } /*****************************************************************************/ int g_tcp_local_socket_stream(void) { - return socket(AF_UNIX, SOCK_STREAM, 0); + return socket(AF_UNIX, SOCK_STREAM, 0); } /*****************************************************************************/ void -g_memcpy(void* d_ptr, const void* s_ptr, int size) +g_memcpy(void *d_ptr, const void *s_ptr, int size) { - memcpy(d_ptr, s_ptr, size); + memcpy(d_ptr, s_ptr, size); } /*****************************************************************************/ int g_tcp_set_no_delay(int sck) { - int i; + int i; - i = 1; - setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (void*)&i, sizeof(i)); - return 0; + i = 1; + setsockopt(sck, IPPROTO_TCP, TCP_NODELAY, (void *)&i, sizeof(i)); + return 0; } /*****************************************************************************/ int g_tcp_set_non_blocking(int sck) { - unsigned long i; + unsigned long i; - i = fcntl(sck, F_GETFL); - i = i | O_NONBLOCK; - fcntl(sck, F_SETFL, i); - return 0; + i = fcntl(sck, F_GETFL); + i = i | O_NONBLOCK; + fcntl(sck, F_SETFL, i); + return 0; } /*****************************************************************************/ int g_tcp_accept(int sck) { - struct sockaddr_in s; - unsigned int i; + struct sockaddr_in s; + unsigned int i; - i = sizeof(struct sockaddr_in); - memset(&s, 0, i); - return accept(sck, (struct sockaddr*)&s, &i); + i = sizeof(struct sockaddr_in); + memset(&s, 0, i); + return accept(sck, (struct sockaddr *)&s, &i); } /*****************************************************************************/ int g_tcp_select(int sck1, int sck2, int sck3) { - fd_set rfds; - struct timeval time; - int max; - int rv; + fd_set rfds; + struct timeval time; + int max; + int rv; - time.tv_sec = 0; - time.tv_usec = 0; - FD_ZERO(&rfds); - if (sck1 > 0) - { - FD_SET(((unsigned int)sck1), &rfds); - } - if (sck2 > 0) - { - FD_SET(((unsigned int)sck2), &rfds); - } - if (sck3 > 0) - { - FD_SET(((unsigned int)sck3), &rfds); - } - max = sck1; - if (sck2 > max) - { - max = sck2; - } - if (sck3 > max) - { - max = sck3; - } - rv = select(max + 1, &rfds, 0, 0, &time); - if (rv > 0) - { - rv = 0; - if (FD_ISSET(((unsigned int)sck1), &rfds)) + time.tv_sec = 0; + time.tv_usec = 0; + FD_ZERO(&rfds); + + if (sck1 > 0) { - rv = rv | 1; + FD_SET(((unsigned int)sck1), &rfds); } - if (FD_ISSET(((unsigned int)sck2), &rfds)) + + if (sck2 > 0) { - rv = rv | 2; + FD_SET(((unsigned int)sck2), &rfds); } - if (FD_ISSET(((unsigned int)sck3), &rfds)) + + if (sck3 > 0) { - rv = rv | 4; + FD_SET(((unsigned int)sck3), &rfds); } - } - else - { - rv = 0; - } - return rv; + + max = sck1; + + if (sck2 > max) + { + max = sck2; + } + + if (sck3 > max) + { + max = sck3; + } + + rv = select(max + 1, &rfds, 0, 0, &time); + + if (rv > 0) + { + rv = 0; + + if (FD_ISSET(((unsigned int)sck1), &rfds)) + { + rv = rv | 1; + } + + if (FD_ISSET(((unsigned int)sck2), &rfds)) + { + rv = rv | 2; + } + + if (FD_ISSET(((unsigned int)sck3), &rfds)) + { + rv = rv | 4; + } + } + else + { + rv = 0; + } + + return rv; } /*****************************************************************************/ int -g_tcp_bind(int sck, char* port) +g_tcp_bind(int sck, char *port) { - struct sockaddr_in s; + struct sockaddr_in s; - memset(&s, 0, sizeof(struct sockaddr_in)); - s.sin_family = AF_INET; - s.sin_port = htons(atoi(port)); - s.sin_addr.s_addr = INADDR_ANY; - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_in)); + memset(&s, 0, sizeof(struct sockaddr_in)); + s.sin_family = AF_INET; + s.sin_port = htons(atoi(port)); + s.sin_addr.s_addr = INADDR_ANY; + return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in)); } /*****************************************************************************/ int -g_tcp_local_bind(int sck, char* port) +g_tcp_local_bind(int sck, char *port) { - struct sockaddr_un s; + struct sockaddr_un s; - memset(&s, 0, sizeof(struct sockaddr_un)); - s.sun_family = AF_UNIX; - strcpy(s.sun_path, port); - return bind(sck, (struct sockaddr*)&s, sizeof(struct sockaddr_un)); + memset(&s, 0, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, port); + return bind(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_un)); } /*****************************************************************************/ int g_tcp_listen(int sck) { - return listen(sck, 2); + return listen(sck, 2); } /*****************************************************************************/ /* returns boolean */ int -g_create_dir(const char* dirname) +g_create_dir(const char *dirname) { - return mkdir(dirname, (mode_t)-1) == 0; + return mkdir(dirname, (mode_t) - 1) == 0; } /*****************************************************************************/ /* returns boolean, non zero if the directory exists */ int -g_directory_exist(const char* dirname) +g_directory_exist(const char *dirname) { - struct stat st; + struct stat st; - if (stat(dirname, &st) == 0) - { - return S_ISDIR(st.st_mode); - } - else - { - return 0; - } + if (stat(dirname, &st) == 0) + { + return S_ISDIR(st.st_mode); + } + else + { + return 0; + } } /*****************************************************************************/ /* returns error */ int -g_chmod_hex(const char* filename, int flags) +g_chmod_hex(const char *filename, int flags) { - int fl; + int fl; - fl = 0; - fl |= (flags & 0x4000) ? S_ISUID : 0; - fl |= (flags & 0x2000) ? S_ISGID : 0; - fl |= (flags & 0x1000) ? S_ISVTX : 0; - fl |= (flags & 0x0400) ? S_IRUSR : 0; - fl |= (flags & 0x0200) ? S_IWUSR : 0; - fl |= (flags & 0x0100) ? S_IXUSR : 0; - fl |= (flags & 0x0040) ? S_IRGRP : 0; - fl |= (flags & 0x0020) ? S_IWGRP : 0; - fl |= (flags & 0x0010) ? S_IXGRP : 0; - fl |= (flags & 0x0004) ? S_IROTH : 0; - fl |= (flags & 0x0002) ? S_IWOTH : 0; - fl |= (flags & 0x0001) ? S_IXOTH : 0; - return chmod(filename, fl); + fl = 0; + fl |= (flags & 0x4000) ? S_ISUID : 0; + fl |= (flags & 0x2000) ? S_ISGID : 0; + fl |= (flags & 0x1000) ? S_ISVTX : 0; + fl |= (flags & 0x0400) ? S_IRUSR : 0; + fl |= (flags & 0x0200) ? S_IWUSR : 0; + fl |= (flags & 0x0100) ? S_IXUSR : 0; + fl |= (flags & 0x0040) ? S_IRGRP : 0; + fl |= (flags & 0x0020) ? S_IWGRP : 0; + fl |= (flags & 0x0010) ? S_IXGRP : 0; + fl |= (flags & 0x0004) ? S_IROTH : 0; + fl |= (flags & 0x0002) ? S_IWOTH : 0; + fl |= (flags & 0x0001) ? S_IXOTH : 0; + return chmod(filename, fl); } /* produce a hex dump */ void -hexdump(unsigned char* p, unsigned int len) +hexdump(unsigned char *p, unsigned int len) { - unsigned char* line; - int i; - int thisline; - int offset; + unsigned char *line; + int i; + int thisline; + int offset; - offset = 0; - line = p; - while (offset < len) - { - ErrorF("%04x ", offset); - thisline = len - offset; - if (thisline > 16) - thisline = 16; + offset = 0; + line = p; - for (i = 0; i < thisline; i++) - ErrorF("%02x ", line[i]); + while (offset < len) + { + ErrorF("%04x ", offset); + thisline = len - offset; - for (; i < 16; i++) - ErrorF(" "); + if (thisline > 16) + { + thisline = 16; + } - for (i = 0; i < thisline; i++) - ErrorF("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); + for (i = 0; i < thisline; i++) + { + ErrorF("%02x ", line[i]); + } - ErrorF("\n"); - offset += thisline; - line += thisline; - } + for (; i < 16; i++) + { + ErrorF(" "); + } + + for (i = 0; i < thisline; i++) + { + ErrorF("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); + } + + ErrorF("\n"); + offset += thisline; + line += thisline; + } } /* @@ -490,26 +515,26 @@ hexdump(unsigned char* p, unsigned int len) Bool XpClientIsBitmapClient(ClientPtr client) { - return 1; + return 1; } /*****************************************************************************/ Bool XpClientIsPrintClient(ClientPtr client, FontPathElementPtr fpe) { - return 0; + return 0; } /*****************************************************************************/ int -PrinterOptions(int argc, char** argv, int i) +PrinterOptions(int argc, char **argv, int i) { - return i; + return i; } /*****************************************************************************/ void -PrinterInitOutput(ScreenInfo* pScreenInfo, int argc, char** argv) +PrinterInitOutput(ScreenInfo *pScreenInfo, int argc, char **argv) { } @@ -533,40 +558,44 @@ FontCacheExtensionInit(INITARGS) /******************************************************************************/ void -RegionAroundSegs(RegionPtr reg, xSegment* segs, int nseg) +RegionAroundSegs(RegionPtr reg, xSegment *segs, int nseg) { - int index; - BoxRec box; - RegionRec treg; + int index; + BoxRec box; + RegionRec treg; - index = 0; - while (index < nseg) - { - if (segs[index].x1 < segs[index].x2) + index = 0; + + while (index < nseg) { - box.x1 = segs[index].x1; - box.x2 = segs[index].x2; + if (segs[index].x1 < segs[index].x2) + { + box.x1 = segs[index].x1; + box.x2 = segs[index].x2; + } + else + { + box.x1 = segs[index].x2; + box.x2 = segs[index].x1; + } + + box.x2++; + + if (segs[index].y1 < segs[index].y2) + { + box.y1 = segs[index].y1; + box.y2 = segs[index].y2; + } + else + { + box.y1 = segs[index].y2; + box.y2 = segs[index].y1; + } + + box.y2++; + RegionInit(&treg, &box, 0); + RegionUnion(reg, reg, &treg); + RegionUninit(&treg); + index++; } - else - { - box.x1 = segs[index].x2; - box.x2 = segs[index].x1; - } - box.x2++; - if (segs[index].y1 < segs[index].y2) - { - box.y1 = segs[index].y1; - box.y2 = segs[index].y2; - } - else - { - box.y1 = segs[index].y2; - box.y2 = segs[index].y1; - } - box.y2++; - RegionInit(&treg, &box, 0); - RegionUnion(reg, reg, &treg); - RegionUninit(&treg); - index++; - } } diff --git a/xorg/X11R7.6/rdp/rdprandr.c b/xorg/X11R7.6/rdp/rdprandr.c index ec011e8f..832d86d4 100644 --- a/xorg/X11R7.6/rdp/rdprandr.c +++ b/xorg/X11R7.6/rdp/rdprandr.c @@ -42,17 +42,17 @@ static XID g_wid = 0; Bool rdpRRRegisterSize(ScreenPtr pScreen, int width, int height) { - int mmwidth; - int mmheight; - RRScreenSizePtr pSize; + int mmwidth; + int mmheight; + RRScreenSizePtr pSize; - ErrorF("rdpRRRegisterSize: width %d height %d\n", width, height); - mmwidth = PixelToMM(width); - mmheight = PixelToMM(height); - pSize = RRRegisterSize(pScreen, width, height, mmwidth, mmheight); - /* Tell RandR what the current config is */ - RRSetCurrentConfig(pScreen, RR_Rotate_0, 0, pSize); - return TRUE; + ErrorF("rdpRRRegisterSize: width %d height %d\n", width, height); + mmwidth = PixelToMM(width); + mmheight = PixelToMM(height); + pSize = RRRegisterSize(pScreen, width, height, mmwidth, mmheight); + /* Tell RandR what the current config is */ + RRSetCurrentConfig(pScreen, RR_Rotate_0, 0, pSize); + return TRUE; } /******************************************************************************/ @@ -60,24 +60,24 @@ Bool rdpRRSetConfig(ScreenPtr pScreen, Rotation rotateKind, int rate, RRScreenSizePtr pSize) { - ErrorF("rdpRRSetConfig:\n"); - return TRUE; + ErrorF("rdpRRSetConfig:\n"); + return TRUE; } /******************************************************************************/ Bool -rdpRRGetInfo(ScreenPtr pScreen, Rotation* pRotations) +rdpRRGetInfo(ScreenPtr pScreen, Rotation *pRotations) { - int width; - int height; + int width; + int height; - ErrorF("rdpRRGetInfo:\n"); - *pRotations = RR_Rotate_0; + ErrorF("rdpRRGetInfo:\n"); + *pRotations = RR_Rotate_0; - width = g_rdpScreen.width; - height = g_rdpScreen.height; - rdpRRRegisterSize(pScreen, width, height); - return TRUE; + width = g_rdpScreen.width; + height = g_rdpScreen.height; + rdpRRRegisterSize(pScreen, width, height); + return TRUE; } /******************************************************************************/ @@ -86,35 +86,39 @@ rdpRRGetInfo(ScreenPtr pScreen, Rotation* pRotations) static int rdpInvalidateArea(ScreenPtr pScreen, int x, int y, int cx, int cy) { - WindowPtr pWin; - int result; - int attri; - XID attributes[4]; - Mask mask; + WindowPtr pWin; + int result; + int attri; + XID attributes[4]; + Mask mask; - DEBUG_OUT(("rdpInvalidateArea:\n")); - mask = 0; - attri = 0; - attributes[attri++] = pScreen->blackPixel; - mask |= CWBackPixel; - attributes[attri++] = xTrue; - mask |= CWOverrideRedirect; - if (g_wid == 0) - { - g_wid = FakeClientID(0); - } - pWin = CreateWindow(g_wid, pScreen->root, - x, y, cx, cy, 0, InputOutput, mask, - attributes, 0, serverClient, - wVisual(pScreen->root), &result); - if (result == 0) - { - g_invalidate_window = pWin; - MapWindow(pWin, serverClient); - DeleteWindow(pWin, None); - g_invalidate_window = pWin; - } - return 0; + DEBUG_OUT(("rdpInvalidateArea:\n")); + mask = 0; + attri = 0; + attributes[attri++] = pScreen->blackPixel; + mask |= CWBackPixel; + attributes[attri++] = xTrue; + mask |= CWOverrideRedirect; + + if (g_wid == 0) + { + g_wid = FakeClientID(0); + } + + pWin = CreateWindow(g_wid, pScreen->root, + x, y, cx, cy, 0, InputOutput, mask, + attributes, 0, serverClient, + wVisual(pScreen->root), &result); + + if (result == 0) + { + g_invalidate_window = pWin; + MapWindow(pWin, serverClient); + DeleteWindow(pWin, None); + g_invalidate_window = pWin; + } + + return 0; } /******************************************************************************/ @@ -122,84 +126,87 @@ Bool rdpRRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight) { - PixmapPtr screenPixmap; - BoxRec box; + PixmapPtr screenPixmap; + BoxRec box; - ErrorF("rdpRRScreenSetSize: width %d height %d mmWidth %d mmHeight %d\n", - width, height, (int)mmWidth, (int)mmHeight); + ErrorF("rdpRRScreenSetSize: width %d height %d mmWidth %d mmHeight %d\n", + width, height, (int)mmWidth, (int)mmHeight); - if ((width < 1) || (height < 1)) - { - ErrorF(" error width %d height %d\n", width, height); - return FALSE; - } - g_rdpScreen.width = width; - g_rdpScreen.height = height; - g_rdpScreen.paddedWidthInBytes = - PixmapBytePad(g_rdpScreen.width, g_rdpScreen.depth); - g_rdpScreen.sizeInBytes = - g_rdpScreen.paddedWidthInBytes * g_rdpScreen.height; - pScreen->width = width; - pScreen->height = height; - pScreen->mmWidth = mmWidth; - pScreen->mmHeight = mmHeight; + if ((width < 1) || (height < 1)) + { + ErrorF(" error width %d height %d\n", width, height); + return FALSE; + } - screenPixmap = pScreen->GetScreenPixmap(pScreen); - if (screenPixmap != 0) - { - ErrorF(" resizing screenPixmap [%p] to %dx%d, currently at %dx%d\n", - (void*)screenPixmap, width, height, - screenPixmap->drawable.width, screenPixmap->drawable.height); - pScreen->ModifyPixmapHeader(screenPixmap, width, height, - g_rdpScreen.depth, g_rdpScreen.bitsPerPixel, - g_rdpScreen.paddedWidthInBytes, - g_rdpScreen.pfbMemory); - ErrorF(" pixmap resized to %dx%d\n", - screenPixmap->drawable.width, screenPixmap->drawable.height); - } - DEBUG_OUT((" root window %p\n", (void*)pScreen->root)); - box.x1 = 0; - box.y1 = 0; - box.x2 = width; - box.y2 = height; - RegionInit(&pScreen->root->winSize, &box, 1); - RegionInit(&pScreen->root->borderSize, &box, 1); - RegionReset(&pScreen->root->borderClip, &box); - RegionBreak(&pScreen->root->clipList); - pScreen->root->drawable.width = width; - pScreen->root->drawable.height = height; - ResizeChildrenWinSize(pScreen->root, 0, 0, 0, 0); - RRScreenSizeNotify(pScreen); - rdpInvalidateArea(g_pScreen, 0, 0, g_rdpScreen.width, g_rdpScreen.height); - ErrorF(" screen resized to %dx%d\n", - pScreen->width, pScreen->height); - return TRUE; + g_rdpScreen.width = width; + g_rdpScreen.height = height; + g_rdpScreen.paddedWidthInBytes = + PixmapBytePad(g_rdpScreen.width, g_rdpScreen.depth); + g_rdpScreen.sizeInBytes = + g_rdpScreen.paddedWidthInBytes * g_rdpScreen.height; + pScreen->width = width; + pScreen->height = height; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + + screenPixmap = pScreen->GetScreenPixmap(pScreen); + + if (screenPixmap != 0) + { + ErrorF(" resizing screenPixmap [%p] to %dx%d, currently at %dx%d\n", + (void *)screenPixmap, width, height, + screenPixmap->drawable.width, screenPixmap->drawable.height); + pScreen->ModifyPixmapHeader(screenPixmap, width, height, + g_rdpScreen.depth, g_rdpScreen.bitsPerPixel, + g_rdpScreen.paddedWidthInBytes, + g_rdpScreen.pfbMemory); + ErrorF(" pixmap resized to %dx%d\n", + screenPixmap->drawable.width, screenPixmap->drawable.height); + } + + DEBUG_OUT((" root window %p\n", (void *)pScreen->root)); + box.x1 = 0; + box.y1 = 0; + box.x2 = width; + box.y2 = height; + RegionInit(&pScreen->root->winSize, &box, 1); + RegionInit(&pScreen->root->borderSize, &box, 1); + RegionReset(&pScreen->root->borderClip, &box); + RegionBreak(&pScreen->root->clipList); + pScreen->root->drawable.width = width; + pScreen->root->drawable.height = height; + ResizeChildrenWinSize(pScreen->root, 0, 0, 0, 0); + RRScreenSizeNotify(pScreen); + rdpInvalidateArea(g_pScreen, 0, 0, g_rdpScreen.width, g_rdpScreen.height); + ErrorF(" screen resized to %dx%d\n", + pScreen->width, pScreen->height); + return TRUE; } /******************************************************************************/ Bool rdpRRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode, int x, int y, Rotation rotation, int numOutputs, - RROutputPtr* outputs) + RROutputPtr *outputs) { - ErrorF("rdpRRCrtcSet:\n"); - return TRUE; + ErrorF("rdpRRCrtcSet:\n"); + return TRUE; } /******************************************************************************/ Bool rdpRRCrtcSetGamma(ScreenPtr pScreen, RRCrtcPtr crtc) { - ErrorF("rdpRRCrtcSetGamma:\n"); - return TRUE; + ErrorF("rdpRRCrtcSetGamma:\n"); + return TRUE; } /******************************************************************************/ Bool rdpRRCrtcGetGamma(ScreenPtr pScreen, RRCrtcPtr crtc) { - ErrorF("rdpRRCrtcGetGamma:\n"); - return TRUE; + ErrorF("rdpRRCrtcGetGamma:\n"); + return TRUE; } /******************************************************************************/ @@ -207,8 +214,8 @@ Bool rdpRROutputSetProperty(ScreenPtr pScreen, RROutputPtr output, Atom property, RRPropertyValuePtr value) { - ErrorF("rdpRROutputSetProperty:\n"); - return TRUE; + ErrorF("rdpRROutputSetProperty:\n"); + return TRUE; } /******************************************************************************/ @@ -216,60 +223,64 @@ Bool rdpRROutputValidateMode(ScreenPtr pScreen, RROutputPtr output, RRModePtr mode) { - ErrorF("rdpRROutputValidateMode:\n"); - return TRUE; + ErrorF("rdpRROutputValidateMode:\n"); + return TRUE; } /******************************************************************************/ void rdpRRModeDestroy(ScreenPtr pScreen, RRModePtr mode) { - ErrorF("rdpRRModeDestroy:\n"); + ErrorF("rdpRRModeDestroy:\n"); } /******************************************************************************/ Bool rdpRROutputGetProperty(ScreenPtr pScreen, RROutputPtr output, Atom property) { - ErrorF("rdpRROutputGetProperty:\n"); - return TRUE; + ErrorF("rdpRROutputGetProperty:\n"); + return TRUE; } /******************************************************************************/ Bool rdpRRGetPanning(ScreenPtr pScrn, RRCrtcPtr crtc, BoxPtr totalArea, - BoxPtr trackingArea, INT16* border) + BoxPtr trackingArea, INT16 *border) { - ErrorF("rdpRRGetPanning:\n"); - if (totalArea != 0) - { - totalArea->x1 = 0; - totalArea->y1 = 0; - totalArea->x2 = g_rdpScreen.width; - totalArea->y2 = g_rdpScreen.height; - } - if (trackingArea != 0) - { - trackingArea->x1 = 0; - trackingArea->y1 = 0; - trackingArea->x2 = g_rdpScreen.width; - trackingArea->y2 = g_rdpScreen.height; - } - if (border != 0) - { - border[0] = 0; - border[1] = 0; - border[2] = 0; - border[3] = 0; - } - return TRUE; + ErrorF("rdpRRGetPanning:\n"); + + if (totalArea != 0) + { + totalArea->x1 = 0; + totalArea->y1 = 0; + totalArea->x2 = g_rdpScreen.width; + totalArea->y2 = g_rdpScreen.height; + } + + if (trackingArea != 0) + { + trackingArea->x1 = 0; + trackingArea->y1 = 0; + trackingArea->x2 = g_rdpScreen.width; + trackingArea->y2 = g_rdpScreen.height; + } + + if (border != 0) + { + border[0] = 0; + border[1] = 0; + border[2] = 0; + border[3] = 0; + } + + return TRUE; } /******************************************************************************/ Bool rdpRRSetPanning(ScreenPtr pScrn, RRCrtcPtr crtc, BoxPtr totalArea, - BoxPtr trackingArea, INT16* border) + BoxPtr trackingArea, INT16 *border) { - ErrorF("rdpRRSetPanning:\n"); - return TRUE; + ErrorF("rdpRRSetPanning:\n"); + return TRUE; } diff --git a/xorg/X11R7.6/rdp/rdpup.c b/xorg/X11R7.6/rdp/rdpup.c index 81165a3a..ac46060e 100644 --- a/xorg/X11R7.6/rdp/rdpup.c +++ b/xorg/X11R7.6/rdp/rdpup.c @@ -24,9 +24,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) int g_con_number = 0; /* increments for each connection */ @@ -40,8 +40,8 @@ static int g_dis_listen_sck = 0; //static int g_dis_connected = 0; static int g_begin = 0; -static struct stream* g_out_s = 0; -static struct stream* g_in_s = 0; +static struct stream *g_out_s = 0; +static struct stream *g_in_s = 0; static int g_button_mask = 0; static int g_cursor_x = 0; static int g_cursor_y = 0; @@ -62,13 +62,13 @@ extern char g_uds_data[]; /* in rdpmain.c */ struct rdpup_os_bitmap { - int used; - PixmapPtr pixmap; - rdpPixmapPtr priv; - int stamp; + int used; + PixmapPtr pixmap; + rdpPixmapPtr priv; + int stamp; }; -static struct rdpup_os_bitmap* g_os_bitmaps = 0; +static struct rdpup_os_bitmap *g_os_bitmaps = 0; static int g_max_os_bitmaps = 0; static int g_os_bitmap_stamp = 0; @@ -96,320 +96,353 @@ f GXset 1 static int g_rdp_opcodes[16] = { - 0x00, /* GXclear 0x0 0 */ - 0x88, /* GXand 0x1 src AND dst */ - 0x44, /* GXandReverse 0x2 src AND NOT dst */ - 0xcc, /* GXcopy 0x3 src */ - 0x22, /* GXandInverted 0x4 NOT src AND dst */ - 0xaa, /* GXnoop 0x5 dst */ - 0x66, /* GXxor 0x6 src XOR dst */ - 0xee, /* GXor 0x7 src OR dst */ - 0x11, /* GXnor 0x8 NOT src AND NOT dst */ - 0x99, /* GXequiv 0x9 NOT src XOR dst */ - 0x55, /* GXinvert 0xa NOT dst */ - 0xdd, /* GXorReverse 0xb src OR NOT dst */ - 0x33, /* GXcopyInverted 0xc NOT src */ - 0xbb, /* GXorInverted 0xd NOT src OR dst */ - 0x77, /* GXnand 0xe NOT src OR NOT dst */ - 0xff /* GXset 0xf 1 */ + 0x00, /* GXclear 0x0 0 */ + 0x88, /* GXand 0x1 src AND dst */ + 0x44, /* GXandReverse 0x2 src AND NOT dst */ + 0xcc, /* GXcopy 0x3 src */ + 0x22, /* GXandInverted 0x4 NOT src AND dst */ + 0xaa, /* GXnoop 0x5 dst */ + 0x66, /* GXxor 0x6 src XOR dst */ + 0xee, /* GXor 0x7 src OR dst */ + 0x11, /* GXnor 0x8 NOT src AND NOT dst */ + 0x99, /* GXequiv 0x9 NOT src XOR dst */ + 0x55, /* GXinvert 0xa NOT dst */ + 0xdd, /* GXorReverse 0xb src OR NOT dst */ + 0x33, /* GXcopyInverted 0xc NOT src */ + 0xbb, /* GXorInverted 0xd NOT src OR dst */ + 0x77, /* GXnand 0xe NOT src OR NOT dst */ + 0xff /* GXset 0xf 1 */ }; /*****************************************************************************/ static int rdpup_disconnect(void) { - int index; + int index; - RemoveEnabledDevice(g_sck); - g_connected = 0; - g_tcp_close(g_sck); - g_sck = 0; - g_sck_closed = 1; - g_pixmap_byte_total = 0; - g_pixmap_num_used = 0; - if (g_max_os_bitmaps > 0) - { - for (index = 0; index < g_max_os_bitmaps; index++) + RemoveEnabledDevice(g_sck); + g_connected = 0; + g_tcp_close(g_sck); + g_sck = 0; + g_sck_closed = 1; + g_pixmap_byte_total = 0; + g_pixmap_num_used = 0; + + if (g_max_os_bitmaps > 0) { - if (g_os_bitmaps[index].used) - { - if (g_os_bitmaps[index].priv != 0) + for (index = 0; index < g_max_os_bitmaps; index++) { - g_os_bitmaps[index].priv->status = 0; + if (g_os_bitmaps[index].used) + { + if (g_os_bitmaps[index].priv != 0) + { + g_os_bitmaps[index].priv->status = 0; + } + } } - } } - } - g_max_os_bitmaps = 0; - g_free(g_os_bitmaps); - g_os_bitmaps = 0; - g_use_rail = 0; - return 0; + + g_max_os_bitmaps = 0; + g_free(g_os_bitmaps); + g_os_bitmaps = 0; + g_use_rail = 0; + return 0; } /*****************************************************************************/ int rdpup_add_os_bitmap(PixmapPtr pixmap, rdpPixmapPtr priv) { - int index; - int rv; - int oldest; - int oldest_index; + int index; + int rv; + int oldest; + int oldest_index; - if (!g_connected) - { - return -1; - } - if (g_os_bitmaps == 0) - { - return -1; - } - rv = -1; - index = 0; - while (index < g_max_os_bitmaps) - { - if (g_os_bitmaps[index].used == 0) + if (!g_connected) { - g_os_bitmaps[index].used = 1; - g_os_bitmaps[index].pixmap = pixmap; - g_os_bitmaps[index].priv = priv; - g_os_bitmaps[index].stamp = g_os_bitmap_stamp; - g_os_bitmap_stamp++; - g_pixmap_num_used++; - rv = index; - break; + return -1; } - index++; - } - if (rv == -1) - { - /* find oldest */ - oldest = 0x7fffffff; - oldest_index = 0; + + if (g_os_bitmaps == 0) + { + return -1; + } + + rv = -1; index = 0; + while (index < g_max_os_bitmaps) { - if (g_os_bitmaps[index].stamp < oldest) - { - oldest = g_os_bitmaps[index].stamp; - oldest_index = index; - } - index++; + if (g_os_bitmaps[index].used == 0) + { + g_os_bitmaps[index].used = 1; + g_os_bitmaps[index].pixmap = pixmap; + g_os_bitmaps[index].priv = priv; + g_os_bitmaps[index].stamp = g_os_bitmap_stamp; + g_os_bitmap_stamp++; + g_pixmap_num_used++; + rv = index; + break; + } + + index++; } - LLOGLN(10, ("rdpup_add_os_bitmap: evicting old, oldest_index %d", oldest_index)); - /* evict old */ - g_os_bitmaps[oldest_index].priv->status = 0; - /* set new */ - g_os_bitmaps[oldest_index].pixmap = pixmap; - g_os_bitmaps[oldest_index].priv = priv; - g_os_bitmaps[oldest_index].stamp = g_os_bitmap_stamp; - g_os_bitmap_stamp++; - rv = oldest_index; - } - LLOGLN(10, ("rdpup_add_os_bitmap: new bitmap index %d", rv)); - LLOGLN(10, (" g_pixmap_num_used %d", g_pixmap_num_used)); - return rv; + + if (rv == -1) + { + /* find oldest */ + oldest = 0x7fffffff; + oldest_index = 0; + index = 0; + + while (index < g_max_os_bitmaps) + { + if (g_os_bitmaps[index].stamp < oldest) + { + oldest = g_os_bitmaps[index].stamp; + oldest_index = index; + } + + index++; + } + + LLOGLN(10, ("rdpup_add_os_bitmap: evicting old, oldest_index %d", oldest_index)); + /* evict old */ + g_os_bitmaps[oldest_index].priv->status = 0; + /* set new */ + g_os_bitmaps[oldest_index].pixmap = pixmap; + g_os_bitmaps[oldest_index].priv = priv; + g_os_bitmaps[oldest_index].stamp = g_os_bitmap_stamp; + g_os_bitmap_stamp++; + rv = oldest_index; + } + + LLOGLN(10, ("rdpup_add_os_bitmap: new bitmap index %d", rv)); + LLOGLN(10, (" g_pixmap_num_used %d", g_pixmap_num_used)); + return rv; } /*****************************************************************************/ int rdpup_remove_os_bitmap(int rdpindex) { - LLOGLN(10, ("rdpup_remove_os_bitmap: index %d stamp %d", - rdpindex, g_os_bitmaps[rdpindex].stamp)); - if (g_os_bitmaps == 0) - { - return 1; - } - if ((rdpindex < 0) && (rdpindex >= g_max_os_bitmaps)) - { - return 1; - } - if (g_os_bitmaps[rdpindex].used) - { - g_os_bitmaps[rdpindex].used = 0; - g_os_bitmaps[rdpindex].pixmap = 0; - g_os_bitmaps[rdpindex].priv = 0; - g_pixmap_num_used--; - } - LLOGLN(10, (" g_pixmap_num_used %d", g_pixmap_num_used)); - return 0; + LLOGLN(10, ("rdpup_remove_os_bitmap: index %d stamp %d", + rdpindex, g_os_bitmaps[rdpindex].stamp)); + + if (g_os_bitmaps == 0) + { + return 1; + } + + if ((rdpindex < 0) && (rdpindex >= g_max_os_bitmaps)) + { + return 1; + } + + if (g_os_bitmaps[rdpindex].used) + { + g_os_bitmaps[rdpindex].used = 0; + g_os_bitmaps[rdpindex].pixmap = 0; + g_os_bitmaps[rdpindex].priv = 0; + g_pixmap_num_used--; + } + + LLOGLN(10, (" g_pixmap_num_used %d", g_pixmap_num_used)); + return 0; } /*****************************************************************************/ /* returns error */ static int -rdpup_send(char* data, int len) +rdpup_send(char *data, int len) { - int sent; + int sent; - LLOGLN(10, ("rdpup_send - sending %d bytes", len)); - if (g_sck_closed) - { - return 1; - } - while (len > 0) - { - sent = g_tcp_send(g_sck, data, len, 0); - if (sent == -1) + LLOGLN(10, ("rdpup_send - sending %d bytes", len)); + + if (g_sck_closed) { - if (g_tcp_last_error_would_block(g_sck)) - { - g_sleep(1); - } - else - { - rdpup_disconnect(); return 1; - } } - else if (sent == 0) + + while (len > 0) { - rdpup_disconnect(); - return 1; + sent = g_tcp_send(g_sck, data, len, 0); + + if (sent == -1) + { + if (g_tcp_last_error_would_block(g_sck)) + { + g_sleep(1); + } + else + { + rdpup_disconnect(); + return 1; + } + } + else if (sent == 0) + { + rdpup_disconnect(); + return 1; + } + else + { + data += sent; + len -= sent; + } } - else - { - data += sent; - len -= sent; - } - } - return 0; + + return 0; } /******************************************************************************/ static int -rdpup_send_msg(struct stream* s) +rdpup_send_msg(struct stream *s) { - int len; - int rv; + int len; + int rv; - rv = 1; - if (s != 0) - { - len = (int)(s->end - s->data); - if (len > s->size) + rv = 1; + + if (s != 0) { - rdpLog("overrun error len %d count %d\n", len, g_count); + len = (int)(s->end - s->data); + + if (len > s->size) + { + rdpLog("overrun error len %d count %d\n", len, g_count); + } + + s_pop_layer(s, iso_hdr); + out_uint16_le(s, 3); + out_uint16_le(s, g_count); + out_uint32_le(s, len - 8); + rv = rdpup_send(s->data, len); } - s_pop_layer(s, iso_hdr); - out_uint16_le(s, 3); - out_uint16_le(s, g_count); - out_uint32_le(s, len - 8); - rv = rdpup_send(s->data, len); - } - if (rv != 0) - { - rdpLog("error in rdpup_send_msg\n"); - } - return rv; + + if (rv != 0) + { + rdpLog("error in rdpup_send_msg\n"); + } + + return rv; } /******************************************************************************/ static int rdpup_send_pending(void) { - if (g_connected && g_begin) - { - LLOGLN(10, ("end %d", g_count)); - out_uint16_le(g_out_s, 2); - out_uint16_le(g_out_s, 4); - g_count++; - s_mark_end(g_out_s); - rdpup_send_msg(g_out_s); - } - g_count = 0; - g_begin = 0; - return 0; + if (g_connected && g_begin) + { + LLOGLN(10, ("end %d", g_count)); + out_uint16_le(g_out_s, 2); + out_uint16_le(g_out_s, 4); + g_count++; + s_mark_end(g_out_s); + rdpup_send_msg(g_out_s); + } + + g_count = 0; + g_begin = 0; + return 0; } /******************************************************************************/ static CARD32 rdpDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) { - rdpup_send_pending(); - g_scheduled = 0; - return 0; + rdpup_send_pending(); + g_scheduled = 0; + return 0; } /******************************************************************************/ static void rdpScheduleDeferredUpdate(void) { - if (!g_scheduled) - { - g_scheduled = 1; - g_timer = TimerSet(g_timer, 0, 40, rdpDeferredUpdateCallback, 0); - } + if (!g_scheduled) + { + g_scheduled = 1; + g_timer = TimerSet(g_timer, 0, 40, rdpDeferredUpdateCallback, 0); + } } /******************************************************************************/ /* returns error */ static int -rdpup_recv(char* data, int len) +rdpup_recv(char *data, int len) { - int rcvd; + int rcvd; - if (g_sck_closed) - { - return 1; - } - while (len > 0) - { - rcvd = g_tcp_recv(g_sck, data, len, 0); - if (rcvd == -1) + if (g_sck_closed) { - if (g_tcp_last_error_would_block(g_sck)) - { - g_sleep(1); - } - else - { - rdpup_disconnect(); return 1; - } } - else if (rcvd == 0) + + while (len > 0) { - rdpup_disconnect(); - return 1; + rcvd = g_tcp_recv(g_sck, data, len, 0); + + if (rcvd == -1) + { + if (g_tcp_last_error_would_block(g_sck)) + { + g_sleep(1); + } + else + { + rdpup_disconnect(); + return 1; + } + } + else if (rcvd == 0) + { + rdpup_disconnect(); + return 1; + } + else + { + data += rcvd; + len -= rcvd; + } } - else - { - data += rcvd; - len -= rcvd; - } - } - return 0; + + return 0; } /******************************************************************************/ static int -rdpup_recv_msg(struct stream* s) +rdpup_recv_msg(struct stream *s) { - int len; - int rv; + int len; + int rv; - rv = 1; - if (s != 0) - { - init_stream(s, 4); - rv = rdpup_recv(s->data, 4); - if (rv == 0) + rv = 1; + + if (s != 0) { - in_uint32_le(s, len); - if (len > 3) - { - init_stream(s, len); - rv = rdpup_recv(s->data, len - 4); - } + init_stream(s, 4); + rv = rdpup_recv(s->data, 4); + + if (rv == 0) + { + in_uint32_le(s, len); + + if (len > 3) + { + init_stream(s, len); + rv = rdpup_recv(s->data, len - 4); + } + } } - } - if (rv != 0) - { - rdpLog("error in rdpup_recv_msg\n"); - } - return rv; + + if (rv != 0) + { + rdpLog("error in rdpup_recv_msg\n"); + } + + return rv; } /******************************************************************************/ @@ -421,1022 +454,1120 @@ rdpup_recv_msg(struct stream* s) static int process_screen_size_msg(int width, int height, int bpp) { - RRScreenSizePtr pSize; - int mmwidth; - int mmheight; - Bool ok; + RRScreenSizePtr pSize; + int mmwidth; + int mmheight; + Bool ok; - LLOGLN(0, ("process_screen_size_msg: set width %d height %d bpp %d", - width, height, bpp)); - g_rdpScreen.rdp_width = width; - g_rdpScreen.rdp_height = height; - g_rdpScreen.rdp_bpp = bpp; - if (bpp < 15) - { - g_rdpScreen.rdp_Bpp = 1; - g_rdpScreen.rdp_Bpp_mask = 0xff; - } - else if (bpp == 15) - { - g_rdpScreen.rdp_Bpp = 2; - g_rdpScreen.rdp_Bpp_mask = 0x7fff; - } - else if (bpp == 16) - { - g_rdpScreen.rdp_Bpp = 2; - g_rdpScreen.rdp_Bpp_mask = 0xffff; - } - else if (bpp > 16) - { - g_rdpScreen.rdp_Bpp = 4; - g_rdpScreen.rdp_Bpp_mask = 0xffffff; - } - mmwidth = PixelToMM(width); - mmheight = PixelToMM(height); + LLOGLN(0, ("process_screen_size_msg: set width %d height %d bpp %d", + width, height, bpp)); + g_rdpScreen.rdp_width = width; + g_rdpScreen.rdp_height = height; + g_rdpScreen.rdp_bpp = bpp; - pSize = RRRegisterSize(g_pScreen, width, height, mmwidth, mmheight); - RRSetCurrentConfig(g_pScreen, RR_Rotate_0, 0, pSize); - if ((g_rdpScreen.width != width) || (g_rdpScreen.height != height)) - { - LLOGLN(0, (" calling RRScreenSizeSet")); - ok = RRScreenSizeSet(g_pScreen, width, height, mmwidth, mmheight); - LLOGLN(0, (" RRScreenSizeSet ok=[%d]", ok)); - } - return 0; + if (bpp < 15) + { + g_rdpScreen.rdp_Bpp = 1; + g_rdpScreen.rdp_Bpp_mask = 0xff; + } + else if (bpp == 15) + { + g_rdpScreen.rdp_Bpp = 2; + g_rdpScreen.rdp_Bpp_mask = 0x7fff; + } + else if (bpp == 16) + { + g_rdpScreen.rdp_Bpp = 2; + g_rdpScreen.rdp_Bpp_mask = 0xffff; + } + else if (bpp > 16) + { + g_rdpScreen.rdp_Bpp = 4; + g_rdpScreen.rdp_Bpp_mask = 0xffffff; + } + + mmwidth = PixelToMM(width); + mmheight = PixelToMM(height); + + pSize = RRRegisterSize(g_pScreen, width, height, mmwidth, mmheight); + RRSetCurrentConfig(g_pScreen, RR_Rotate_0, 0, pSize); + + if ((g_rdpScreen.width != width) || (g_rdpScreen.height != height)) + { + LLOGLN(0, (" calling RRScreenSizeSet")); + ok = RRScreenSizeSet(g_pScreen, width, height, mmwidth, mmheight); + LLOGLN(0, (" RRScreenSizeSet ok=[%d]", ok)); + } + + return 0; } /******************************************************************************/ static int l_bound_by(int val, int low, int high) { - if (val > high) - { - val = high; - } - if (val < low) - { - val = low; - } - return val; + if (val > high) + { + val = high; + } + + if (val < low) + { + val = low; + } + + return val; } /******************************************************************************/ static int rdpup_send_caps(void) { - struct stream* ls; - int len; - int rv; - int cap_count; - int cap_bytes; + struct stream *ls; + int len; + int rv; + int cap_count; + int cap_bytes; - make_stream(ls); - init_stream(ls, 8192); - s_push_layer(ls, iso_hdr, 8); + make_stream(ls); + init_stream(ls, 8192); + s_push_layer(ls, iso_hdr, 8); - cap_count = 0; - cap_bytes = 0; + cap_count = 0; + cap_bytes = 0; #if 0 - out_uint16_le(ls, 0); - out_uint16_le(ls, 4); - cap_count++; - cap_bytes += 4; + out_uint16_le(ls, 0); + out_uint16_le(ls, 4); + cap_count++; + cap_bytes += 4; - out_uint16_le(ls, 1); - out_uint16_le(ls, 4); - cap_count++; - cap_bytes += 4; + out_uint16_le(ls, 1); + out_uint16_le(ls, 4); + cap_count++; + cap_bytes += 4; #endif - s_mark_end(ls); - len = (int)(ls->end - ls->data); - s_pop_layer(ls, iso_hdr); - out_uint16_le(ls, 2); /* caps */ - out_uint16_le(ls, cap_count); /* num caps */ - out_uint32_le(ls, cap_bytes); /* caps len after header */ + s_mark_end(ls); + len = (int)(ls->end - ls->data); + s_pop_layer(ls, iso_hdr); + out_uint16_le(ls, 2); /* caps */ + out_uint16_le(ls, cap_count); /* num caps */ + out_uint32_le(ls, cap_bytes); /* caps len after header */ - rv = rdpup_send(ls->data, len); - if (rv != 0) - { - LLOGLN(0, ("rdpup_send_caps: rdpup_send failed")); - } - free_stream(ls); - return rv; + rv = rdpup_send(ls->data, len); + + if (rv != 0) + { + LLOGLN(0, ("rdpup_send_caps: rdpup_send failed")); + } + + free_stream(ls); + return rv; } /******************************************************************************/ static int process_version_msg(int param1, int param2, int param3, int param4) { - LLOGLN(0, ("process_version_msg: version %d %d %d %d", param1, param2, - param3, param4)); - if ((param1 > 0) || (param2 > 0) || (param3 > 0) || (param4 > 0)) - { - rdpup_send_caps(); - } - return 0; + LLOGLN(0, ("process_version_msg: version %d %d %d %d", param1, param2, + param3, param4)); + + if ((param1 > 0) || (param2 > 0) || (param3 > 0) || (param4 > 0)) + { + rdpup_send_caps(); + } + + return 0; } /******************************************************************************/ static int -rdpup_process_msg(struct stream* s) +rdpup_process_msg(struct stream *s) { - int msg_type; - int msg; - int param1; - int param2; - int param3; - int param4; - int bytes; - int i1; + int msg_type; + int msg; + int param1; + int param2; + int param3; + int param4; + int bytes; + int i1; - in_uint16_le(s, msg_type); - if (msg_type == 103) - { - in_uint32_le(s, msg); - in_uint32_le(s, param1); - in_uint32_le(s, param2); - in_uint32_le(s, param3); - in_uint32_le(s, param4); - LLOGLN(10, ("rdpup_process_msg - msg %d param1 %d param2 %d param3 %d " - "param4 %d", msg, param1, param2, param3, param4)); - switch (msg) + in_uint16_le(s, msg_type); + + if (msg_type == 103) { - case 15: /* key down */ - case 16: /* key up */ - KbdAddEvent(msg == 15, param1, param2, param3, param4); - break; - case 17: /* from RDP_INPUT_SYNCHRONIZE */ - KbdSync(param1); - break; - case 100: - /* without the minus 2, strange things happen when dragging - past the width or height */ - g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); - g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 101: - g_button_mask = g_button_mask & (~1); - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 102: - g_button_mask = g_button_mask | 1; - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 103: - g_button_mask = g_button_mask & (~4); - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 104: - g_button_mask = g_button_mask | 4; - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 105: - g_button_mask = g_button_mask & (~2); - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 106: - g_button_mask = g_button_mask | 2; - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 107: - g_button_mask = g_button_mask & (~8); - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 108: - g_button_mask = g_button_mask | 8; - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 109: - g_button_mask = g_button_mask & (~16); - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 110: - g_button_mask = g_button_mask | 16; - PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); - break; - case 200: - rdpup_begin_update(); - rdpup_send_area(0, (param1 >> 16) & 0xffff, param1 & 0xffff, - (param2 >> 16) & 0xffff, param2 & 0xffff); - rdpup_end_update(); - break; - case 300: - process_screen_size_msg(param1, param2, param3); - break; - case 301: - process_version_msg(param1, param2, param3, param4); - break; + in_uint32_le(s, msg); + in_uint32_le(s, param1); + in_uint32_le(s, param2); + in_uint32_le(s, param3); + in_uint32_le(s, param4); + LLOGLN(10, ("rdpup_process_msg - msg %d param1 %d param2 %d param3 %d " + "param4 %d", msg, param1, param2, param3, param4)); + + switch (msg) + { + case 15: /* key down */ + case 16: /* key up */ + KbdAddEvent(msg == 15, param1, param2, param3, param4); + break; + case 17: /* from RDP_INPUT_SYNCHRONIZE */ + KbdSync(param1); + break; + case 100: + /* without the minus 2, strange things happen when dragging + past the width or height */ + g_cursor_x = l_bound_by(param1, 0, g_rdpScreen.width - 2); + g_cursor_y = l_bound_by(param2, 0, g_rdpScreen.height - 2); + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 101: + g_button_mask = g_button_mask & (~1); + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 102: + g_button_mask = g_button_mask | 1; + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 103: + g_button_mask = g_button_mask & (~4); + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 104: + g_button_mask = g_button_mask | 4; + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 105: + g_button_mask = g_button_mask & (~2); + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 106: + g_button_mask = g_button_mask | 2; + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 107: + g_button_mask = g_button_mask & (~8); + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 108: + g_button_mask = g_button_mask | 8; + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 109: + g_button_mask = g_button_mask & (~16); + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 110: + g_button_mask = g_button_mask | 16; + PtrAddEvent(g_button_mask, g_cursor_x, g_cursor_y); + break; + case 200: + rdpup_begin_update(); + rdpup_send_area(0, (param1 >> 16) & 0xffff, param1 & 0xffff, + (param2 >> 16) & 0xffff, param2 & 0xffff); + rdpup_end_update(); + break; + case 300: + process_screen_size_msg(param1, param2, param3); + break; + case 301: + process_version_msg(param1, param2, param3, param4); + break; + } } - } - else if (msg_type == 104) - { - in_uint32_le(s, bytes); - if (bytes > sizeof(g_rdpScreen.client_info)) + else if (msg_type == 104) { - bytes = sizeof(g_rdpScreen.client_info); + in_uint32_le(s, bytes); + + if (bytes > sizeof(g_rdpScreen.client_info)) + { + bytes = sizeof(g_rdpScreen.client_info); + } + + memcpy(&(g_rdpScreen.client_info), s->p - 4, bytes); + g_rdpScreen.client_info.size = bytes; + LLOGLN(0, ("rdpup_process_msg: got client info bytes %d", bytes)); + LLOGLN(0, (" jpeg support %d", g_rdpScreen.client_info.jpeg)); + i1 = g_rdpScreen.client_info.offscreen_support_level; + LLOGLN(0, (" offscreen support %d", i1)); + i1 = g_rdpScreen.client_info.offscreen_cache_size; + LLOGLN(0, (" offscreen size %d", i1)); + i1 = g_rdpScreen.client_info.offscreen_cache_entries; + LLOGLN(0, (" offscreen entries %d", i1)); + + if (g_rdpScreen.client_info.offscreen_support_level > 0) + { + if (g_rdpScreen.client_info.offscreen_cache_entries > 0) + { + g_max_os_bitmaps = g_rdpScreen.client_info.offscreen_cache_entries; + g_free(g_os_bitmaps); + g_os_bitmaps = (struct rdpup_os_bitmap *) + g_malloc(sizeof(struct rdpup_os_bitmap) * g_max_os_bitmaps, 1); + } + } + + if (g_rdpScreen.client_info.rail_support_level > 0) + { + g_use_rail = 1; + } } - memcpy(&(g_rdpScreen.client_info), s->p - 4, bytes); - g_rdpScreen.client_info.size = bytes; - LLOGLN(0, ("rdpup_process_msg: got client info bytes %d", bytes)); - LLOGLN(0, (" jpeg support %d", g_rdpScreen.client_info.jpeg)); - i1 = g_rdpScreen.client_info.offscreen_support_level; - LLOGLN(0, (" offscreen support %d", i1)); - i1 = g_rdpScreen.client_info.offscreen_cache_size; - LLOGLN(0, (" offscreen size %d", i1)); - i1 = g_rdpScreen.client_info.offscreen_cache_entries; - LLOGLN(0, (" offscreen entries %d", i1)); - if (g_rdpScreen.client_info.offscreen_support_level > 0) + else { - if (g_rdpScreen.client_info.offscreen_cache_entries > 0) - { - g_max_os_bitmaps = g_rdpScreen.client_info.offscreen_cache_entries; - g_free(g_os_bitmaps); - g_os_bitmaps = (struct rdpup_os_bitmap*) - g_malloc(sizeof(struct rdpup_os_bitmap) * g_max_os_bitmaps, 1); - } + rdpLog("unknown message type in rdpup_process_msg %d\n", msg_type); } - if (g_rdpScreen.client_info.rail_support_level > 0) - { - g_use_rail = 1; - } - } - else - { - rdpLog("unknown message type in rdpup_process_msg %d\n", msg_type); - } - return 0; + + return 0; } /******************************************************************************/ void -rdpup_get_screen_image_rect(struct image_data* id) +rdpup_get_screen_image_rect(struct image_data *id) { - id->width = g_rdpScreen.width; - id->height = g_rdpScreen.height; - id->bpp = g_rdpScreen.rdp_bpp; - id->Bpp = g_rdpScreen.rdp_Bpp; - id->lineBytes = g_rdpScreen.paddedWidthInBytes; - id->pixels = g_rdpScreen.pfbMemory; + id->width = g_rdpScreen.width; + id->height = g_rdpScreen.height; + id->bpp = g_rdpScreen.rdp_bpp; + id->Bpp = g_rdpScreen.rdp_Bpp; + id->lineBytes = g_rdpScreen.paddedWidthInBytes; + id->pixels = g_rdpScreen.pfbMemory; } /******************************************************************************/ void -rdpup_get_pixmap_image_rect(PixmapPtr pPixmap, struct image_data* id) +rdpup_get_pixmap_image_rect(PixmapPtr pPixmap, struct image_data *id) { - id->width = pPixmap->drawable.width; - id->height = pPixmap->drawable.height; - id->bpp = g_rdpScreen.rdp_bpp; - id->Bpp = g_rdpScreen.rdp_Bpp; - id->lineBytes = pPixmap->devKind; - id->pixels = (char*)(pPixmap->devPrivate.ptr); + id->width = pPixmap->drawable.width; + id->height = pPixmap->drawable.height; + id->bpp = g_rdpScreen.rdp_bpp; + id->Bpp = g_rdpScreen.rdp_Bpp; + id->lineBytes = pPixmap->devKind; + id->pixels = (char *)(pPixmap->devPrivate.ptr); } /******************************************************************************/ int rdpup_init(void) { - char text[256]; - int i; + char text[256]; + int i; - if (!g_directory_exist("/tmp/.xrdp")) - { - if (!g_create_dir("/tmp/.xrdp")) + if (!g_directory_exist("/tmp/.xrdp")) { - LLOGLN(0, ("rdpup_init: g_create_dir failed")); - return 0; + if (!g_create_dir("/tmp/.xrdp")) + { + LLOGLN(0, ("rdpup_init: g_create_dir failed")); + return 0; + } + + g_chmod_hex("/tmp/.xrdp", 0x1777); } - g_chmod_hex("/tmp/.xrdp", 0x1777); - } - i = atoi(display); - if (i < 1) - { - return 0; - } - if (g_in_s == 0) - { - make_stream(g_in_s); - init_stream(g_in_s, 8192); - } - if (g_out_s == 0) - { - make_stream(g_out_s); - init_stream(g_out_s, 8192 * g_Bpp + 100); - } - if (g_use_uds) - { - g_sprintf(g_uds_data, "/tmp/.xrdp/xrdp_display_%s", display); - if (g_listen_sck == 0) + + i = atoi(display); + + if (i < 1) { - g_listen_sck = g_tcp_local_socket_stream(); - if (g_tcp_local_bind(g_listen_sck, g_uds_data) != 0) - { - LLOGLN(0, ("rdpup_init: g_tcp_local_bind failed")); return 0; - } - g_tcp_listen(g_listen_sck); - AddEnabledDevice(g_listen_sck); } - } - else - { - g_sprintf(text, "62%2.2d", i); - if (g_listen_sck == 0) + + if (g_in_s == 0) { - g_listen_sck = g_tcp_socket(); - if (g_tcp_bind(g_listen_sck, text) != 0) - { - return 0; - } - g_tcp_listen(g_listen_sck); - AddEnabledDevice(g_listen_sck); + make_stream(g_in_s); + init_stream(g_in_s, 8192); } - } - g_dis_listen_sck = g_tcp_local_socket_dgram(); - if (g_dis_listen_sck != 0) - { - g_sprintf(text, "/tmp/.xrdp/xrdp_disconnect_display_%s", display); - if (g_tcp_local_bind(g_dis_listen_sck, text) == 0) + + if (g_out_s == 0) { - AddEnabledDevice(g_dis_listen_sck); + make_stream(g_out_s); + init_stream(g_out_s, 8192 * g_Bpp + 100); + } + + if (g_use_uds) + { + g_sprintf(g_uds_data, "/tmp/.xrdp/xrdp_display_%s", display); + + if (g_listen_sck == 0) + { + g_listen_sck = g_tcp_local_socket_stream(); + + if (g_tcp_local_bind(g_listen_sck, g_uds_data) != 0) + { + LLOGLN(0, ("rdpup_init: g_tcp_local_bind failed")); + return 0; + } + + g_tcp_listen(g_listen_sck); + AddEnabledDevice(g_listen_sck); + } } else { - rdpLog("g_tcp_local_bind failed [%s]\n", text); + g_sprintf(text, "62%2.2d", i); + + if (g_listen_sck == 0) + { + g_listen_sck = g_tcp_socket(); + + if (g_tcp_bind(g_listen_sck, text) != 0) + { + return 0; + } + + g_tcp_listen(g_listen_sck); + AddEnabledDevice(g_listen_sck); + } } - } - return 1; + + g_dis_listen_sck = g_tcp_local_socket_dgram(); + + if (g_dis_listen_sck != 0) + { + g_sprintf(text, "/tmp/.xrdp/xrdp_disconnect_display_%s", display); + + if (g_tcp_local_bind(g_dis_listen_sck, text) == 0) + { + AddEnabledDevice(g_dis_listen_sck); + } + else + { + rdpLog("g_tcp_local_bind failed [%s]\n", text); + } + } + + return 1; } /******************************************************************************/ int rdpup_check(void) { - int sel; - int new_sck; - char buf[8]; + int sel; + int new_sck; + char buf[8]; - sel = g_tcp_select(g_listen_sck, g_sck, g_dis_listen_sck); - if (sel & 1) - { - new_sck = g_tcp_accept(g_listen_sck); - if (new_sck == -1) + sel = g_tcp_select(g_listen_sck, g_sck, g_dis_listen_sck); + + if (sel & 1) { + new_sck = g_tcp_accept(g_listen_sck); + + if (new_sck == -1) + { + } + else + { + if (g_sck != 0) + { + /* should maybe ask is user wants to allow here with timeout */ + rdpLog("replacing connection, already got a connection\n"); + rdpup_disconnect(); + } + + rdpLog("got a connection\n"); + g_sck = new_sck; + g_tcp_set_non_blocking(g_sck); + g_tcp_set_no_delay(g_sck); + g_connected = 1; + g_sck_closed = 0; + g_begin = 0; + g_con_number++; + AddEnabledDevice(g_sck); + } } - else + + if (sel & 2) { - if (g_sck != 0) - { - /* should maybe ask is user wants to allow here with timeout */ - rdpLog("replacing connection, already got a connection\n"); - rdpup_disconnect(); - } - rdpLog("got a connection\n"); - g_sck = new_sck; - g_tcp_set_non_blocking(g_sck); - g_tcp_set_no_delay(g_sck); - g_connected = 1; - g_sck_closed = 0; - g_begin = 0; - g_con_number++; - AddEnabledDevice(g_sck); + if (rdpup_recv_msg(g_in_s) == 0) + { + rdpup_process_msg(g_in_s); + } } - } - if (sel & 2) - { - if (rdpup_recv_msg(g_in_s) == 0) + + if (sel & 4) { - rdpup_process_msg(g_in_s); + if (g_tcp_recv(g_dis_listen_sck, buf, 4, 0) > 0) + { + if (g_sck != 0) + { + rdpLog("disconnecting session via user request\n"); + rdpup_disconnect(); + } + } } - } - if (sel & 4) - { - if (g_tcp_recv(g_dis_listen_sck, buf, 4, 0) > 0) - { - if (g_sck != 0) - { - rdpLog("disconnecting session via user request\n"); - rdpup_disconnect(); - } - } - } - return 0; + + return 0; } /******************************************************************************/ int rdpup_begin_update(void) { - if (g_connected) - { - if (g_begin) + if (g_connected) { - return 0; + if (g_begin) + { + return 0; + } + + init_stream(g_out_s, 0); + s_push_layer(g_out_s, iso_hdr, 8); + out_uint16_le(g_out_s, 1); /* begin update */ + out_uint16_le(g_out_s, 4); /* size */ + LLOGLN(10, ("begin %d", g_count)); + g_begin = 1; + g_count = 1; } - init_stream(g_out_s, 0); - s_push_layer(g_out_s, iso_hdr, 8); - out_uint16_le(g_out_s, 1); /* begin update */ - out_uint16_le(g_out_s, 4); /* size */ - LLOGLN(10, ("begin %d", g_count)); - g_begin = 1; - g_count = 1; - } - return 0; + + return 0; } /******************************************************************************/ int rdpup_end_update(void) { - if (g_connected && g_begin) - { - rdpScheduleDeferredUpdate(); - } - return 0; + if (g_connected && g_begin) + { + rdpScheduleDeferredUpdate(); + } + + return 0; } /******************************************************************************/ int rdpup_pre_check(int in_size) { - if (!g_begin) - { - rdpup_begin_update(); - } - if ((g_out_s->p - g_out_s->data) > (g_out_s->size - (in_size + 20))) - { - s_mark_end(g_out_s); - rdpup_send_msg(g_out_s); - g_count = 0; - init_stream(g_out_s, 0); - s_push_layer(g_out_s, iso_hdr, 8); - } - return 0; + if (!g_begin) + { + rdpup_begin_update(); + } + + if ((g_out_s->p - g_out_s->data) > (g_out_s->size - (in_size + 20))) + { + s_mark_end(g_out_s); + rdpup_send_msg(g_out_s); + g_count = 0; + init_stream(g_out_s, 0); + s_push_layer(g_out_s, iso_hdr, 8); + } + + return 0; } /******************************************************************************/ int rdpup_fill_rect(short x, short y, int cx, int cy) { - if (g_connected) - { - LLOGLN(10, (" rdpup_fill_rect")); - rdpup_pre_check(12); - out_uint16_le(g_out_s, 3); /* fill rect */ - out_uint16_le(g_out_s, 12); /* size */ - g_count++; - out_uint16_le(g_out_s, x); - out_uint16_le(g_out_s, y); - out_uint16_le(g_out_s, cx); - out_uint16_le(g_out_s, cy); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_fill_rect")); + rdpup_pre_check(12); + out_uint16_le(g_out_s, 3); /* fill rect */ + out_uint16_le(g_out_s, 12); /* size */ + g_count++; + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, cx); + out_uint16_le(g_out_s, cy); + } + + return 0; } /******************************************************************************/ int rdpup_screen_blt(short x, short y, int cx, int cy, short srcx, short srcy) { - if (g_connected) - { - LLOGLN(10, (" rdpup_screen_blt")); - rdpup_pre_check(16); - out_uint16_le(g_out_s, 4); /* screen blt */ - out_uint16_le(g_out_s, 16); /* size */ - g_count++; - out_uint16_le(g_out_s, x); - out_uint16_le(g_out_s, y); - out_uint16_le(g_out_s, cx); - out_uint16_le(g_out_s, cy); - out_uint16_le(g_out_s, srcx); - out_uint16_le(g_out_s, srcy); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_screen_blt")); + rdpup_pre_check(16); + out_uint16_le(g_out_s, 4); /* screen blt */ + out_uint16_le(g_out_s, 16); /* size */ + g_count++; + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, cx); + out_uint16_le(g_out_s, cy); + out_uint16_le(g_out_s, srcx); + out_uint16_le(g_out_s, srcy); + } + + return 0; } /******************************************************************************/ int rdpup_set_clip(short x, short y, int cx, int cy) { - if (g_connected) - { - LLOGLN(10, (" rdpup_set_clip")); - rdpup_pre_check(12); - out_uint16_le(g_out_s, 10); /* set clip */ - out_uint16_le(g_out_s, 12); /* size */ - g_count++; - out_uint16_le(g_out_s, x); - out_uint16_le(g_out_s, y); - out_uint16_le(g_out_s, cx); - out_uint16_le(g_out_s, cy); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_set_clip")); + rdpup_pre_check(12); + out_uint16_le(g_out_s, 10); /* set clip */ + out_uint16_le(g_out_s, 12); /* size */ + g_count++; + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, cx); + out_uint16_le(g_out_s, cy); + } + + return 0; } /******************************************************************************/ int rdpup_reset_clip(void) { - if (g_connected) - { - LLOGLN(10, (" rdpup_reset_clip")); - rdpup_pre_check(4); - out_uint16_le(g_out_s, 11); /* reset clip */ - out_uint16_le(g_out_s, 4); /* size */ - g_count++; - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_reset_clip")); + rdpup_pre_check(4); + out_uint16_le(g_out_s, 11); /* reset clip */ + out_uint16_le(g_out_s, 4); /* size */ + g_count++; + } + + return 0; } #define COLOR8(r, g, b) \ - ((((r) >> 5) << 0) | (((g) >> 5) << 3) | (((b) >> 6) << 6)) + ((((r) >> 5) << 0) | (((g) >> 5) << 3) | (((b) >> 6) << 6)) #define COLOR15(r, g, b) \ - ((((r) >> 3) << 10) | (((g) >> 3) << 5) | (((b) >> 3) << 0)) + ((((r) >> 3) << 10) | (((g) >> 3) << 5) | (((b) >> 3) << 0)) #define COLOR16(r, g, b) \ - ((((r) >> 3) << 11) | (((g) >> 2) << 5) | (((b) >> 3) << 0)) + ((((r) >> 3) << 11) | (((g) >> 2) << 5) | (((b) >> 3) << 0)) #define COLOR24(r, g, b) \ - ((((r) >> 0) << 0) | (((g) >> 0) << 8) | (((b) >> 0) << 16)) + ((((r) >> 0) << 0) | (((g) >> 0) << 8) | (((b) >> 0) << 16)) #define SPLITCOLOR32(r, g, b, c) \ -{ \ - r = ((c) >> 16) & 0xff; \ - g = ((c) >> 8) & 0xff; \ - b = (c) & 0xff; \ -} + { \ + r = ((c) >> 16) & 0xff; \ + g = ((c) >> 8) & 0xff; \ + b = (c) & 0xff; \ + } int convert_pixel(int in_pixel) { - int red; - int green; - int blue; - int rv; + int red; + int green; + int blue; + int rv; - rv = 0; - if (g_rdpScreen.depth == 24) - { - if (g_rdpScreen.rdp_bpp == 24) + rv = 0; + + if (g_rdpScreen.depth == 24) { - rv = in_pixel; - SPLITCOLOR32(red, green, blue, rv); - rv = COLOR24(red, green, blue); + if (g_rdpScreen.rdp_bpp == 24) + { + rv = in_pixel; + SPLITCOLOR32(red, green, blue, rv); + rv = COLOR24(red, green, blue); + } + else if (g_rdpScreen.rdp_bpp == 16) + { + rv = in_pixel; + SPLITCOLOR32(red, green, blue, rv); + rv = COLOR16(red, green, blue); + } + else if (g_rdpScreen.rdp_bpp == 15) + { + rv = in_pixel; + SPLITCOLOR32(red, green, blue, rv); + rv = COLOR15(red, green, blue); + } + else if (g_rdpScreen.rdp_bpp == 8) + { + rv = in_pixel; + SPLITCOLOR32(red, green, blue, rv); + rv = COLOR8(red, green, blue); + } } - else if (g_rdpScreen.rdp_bpp == 16) + else if (g_rdpScreen.depth == g_rdpScreen.rdp_bpp) { - rv = in_pixel; - SPLITCOLOR32(red, green, blue, rv); - rv = COLOR16(red, green, blue); + return in_pixel; } - else if (g_rdpScreen.rdp_bpp == 15) - { - rv = in_pixel; - SPLITCOLOR32(red, green, blue, rv); - rv = COLOR15(red, green, blue); - } - else if (g_rdpScreen.rdp_bpp == 8) - { - rv = in_pixel; - SPLITCOLOR32(red, green, blue, rv); - rv = COLOR8(red, green, blue); - } - } - else if (g_rdpScreen.depth == g_rdpScreen.rdp_bpp) - { - return in_pixel; - } - return rv; + + return rv; } int -convert_pixels(void* src, void* dst, int num_pixels) +convert_pixels(void *src, void *dst, int num_pixels) { - unsigned int pixel; - unsigned int red; - unsigned int green; - unsigned int blue; - unsigned int* src32; - unsigned int* dst32; - unsigned short* dst16; - unsigned char* dst8; - int index; + unsigned int pixel; + unsigned int red; + unsigned int green; + unsigned int blue; + unsigned int *src32; + unsigned int *dst32; + unsigned short *dst16; + unsigned char *dst8; + int index; + + if (g_rdpScreen.depth == g_rdpScreen.rdp_bpp) + { + memcpy(dst, src, num_pixels * g_Bpp); + return 0; + } + + if (g_rdpScreen.depth == 24) + { + src32 = (unsigned int *)src; + + if (g_rdpScreen.rdp_bpp == 24) + { + dst32 = (unsigned int *)dst; + + for (index = 0; index < num_pixels; index++) + { + pixel = *src32; + *dst32 = pixel; + dst32++; + src32++; + } + } + else if (g_rdpScreen.rdp_bpp == 16) + { + dst16 = (unsigned short *)dst; + + for (index = 0; index < num_pixels; index++) + { + pixel = *src32; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR16(red, green, blue); + *dst16 = pixel; + dst16++; + src32++; + } + } + else if (g_rdpScreen.rdp_bpp == 15) + { + dst16 = (unsigned short *)dst; + + for (index = 0; index < num_pixels; index++) + { + pixel = *src32; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR15(red, green, blue); + *dst16 = pixel; + dst16++; + src32++; + } + } + else if (g_rdpScreen.rdp_bpp == 8) + { + dst8 = (unsigned char *)dst; + + for (index = 0; index < num_pixels; index++) + { + pixel = *src32; + SPLITCOLOR32(red, green, blue, pixel); + pixel = COLOR8(red, green, blue); + *dst8 = pixel; + dst8++; + src32++; + } + } + } - if (g_rdpScreen.depth == g_rdpScreen.rdp_bpp) - { - memcpy(dst, src, num_pixels * g_Bpp); return 0; - } - if (g_rdpScreen.depth == 24) - { - src32 = (unsigned int*)src; - if (g_rdpScreen.rdp_bpp == 24) - { - dst32 = (unsigned int*)dst; - for (index = 0; index < num_pixels; index++) - { - pixel = *src32; - *dst32 = pixel; - dst32++; - src32++; - } - } - else if (g_rdpScreen.rdp_bpp == 16) - { - dst16 = (unsigned short*)dst; - for (index = 0; index < num_pixels; index++) - { - pixel = *src32; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR16(red, green, blue); - *dst16 = pixel; - dst16++; - src32++; - } - } - else if (g_rdpScreen.rdp_bpp == 15) - { - dst16 = (unsigned short*)dst; - for (index = 0; index < num_pixels; index++) - { - pixel = *src32; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR15(red, green, blue); - *dst16 = pixel; - dst16++; - src32++; - } - } - else if (g_rdpScreen.rdp_bpp == 8) - { - dst8 = (unsigned char*)dst; - for (index = 0; index < num_pixels; index++) - { - pixel = *src32; - SPLITCOLOR32(red, green, blue, pixel); - pixel = COLOR8(red, green, blue); - *dst8 = pixel; - dst8++; - src32++; - } - } - } - return 0; } /******************************************************************************/ int rdpup_set_fgcolor(int fgcolor) { - if (g_connected) - { - LLOGLN(10, (" rdpup_set_fgcolor")); - rdpup_pre_check(8); - out_uint16_le(g_out_s, 12); /* set fgcolor */ - out_uint16_le(g_out_s, 8); /* size */ - g_count++; - fgcolor = fgcolor & g_Bpp_mask; - fgcolor = convert_pixel(fgcolor) & g_rdpScreen.rdp_Bpp_mask; - out_uint32_le(g_out_s, fgcolor); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_set_fgcolor")); + rdpup_pre_check(8); + out_uint16_le(g_out_s, 12); /* set fgcolor */ + out_uint16_le(g_out_s, 8); /* size */ + g_count++; + fgcolor = fgcolor & g_Bpp_mask; + fgcolor = convert_pixel(fgcolor) & g_rdpScreen.rdp_Bpp_mask; + out_uint32_le(g_out_s, fgcolor); + } + + return 0; } /******************************************************************************/ int rdpup_set_bgcolor(int bgcolor) { - if (g_connected) - { - LLOGLN(10, (" rdpup_set_bgcolor")); - rdpup_pre_check(8); - out_uint16_le(g_out_s, 13); /* set bg color */ - out_uint16_le(g_out_s, 8); /* size */ - g_count++; - bgcolor = bgcolor & g_Bpp_mask; - bgcolor = convert_pixel(bgcolor) & g_rdpScreen.rdp_Bpp_mask; - out_uint32_le(g_out_s, bgcolor); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_set_bgcolor")); + rdpup_pre_check(8); + out_uint16_le(g_out_s, 13); /* set bg color */ + out_uint16_le(g_out_s, 8); /* size */ + g_count++; + bgcolor = bgcolor & g_Bpp_mask; + bgcolor = convert_pixel(bgcolor) & g_rdpScreen.rdp_Bpp_mask; + out_uint32_le(g_out_s, bgcolor); + } + + return 0; } /******************************************************************************/ int rdpup_set_opcode(int opcode) { - if (g_connected) - { - LLOGLN(10, (" rdpup_set_opcode")); - rdpup_pre_check(6); - out_uint16_le(g_out_s, 14); /* set opcode */ - out_uint16_le(g_out_s, 6); /* size */ - g_count++; - out_uint16_le(g_out_s, g_rdp_opcodes[opcode & 0xf]); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_set_opcode")); + rdpup_pre_check(6); + out_uint16_le(g_out_s, 14); /* set opcode */ + out_uint16_le(g_out_s, 6); /* size */ + g_count++; + out_uint16_le(g_out_s, g_rdp_opcodes[opcode & 0xf]); + } + + return 0; } /******************************************************************************/ int rdpup_set_pen(int style, int width) { - if (g_connected) - { - LLOGLN(10, (" rdpup_set_pen")); - rdpup_pre_check(8); - out_uint16_le(g_out_s, 17); /* set pen */ - out_uint16_le(g_out_s, 8); /* size */ - g_count++; - out_uint16_le(g_out_s, style); - out_uint16_le(g_out_s, width); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_set_pen")); + rdpup_pre_check(8); + out_uint16_le(g_out_s, 17); /* set pen */ + out_uint16_le(g_out_s, 8); /* size */ + g_count++; + out_uint16_le(g_out_s, style); + out_uint16_le(g_out_s, width); + } + + return 0; } /******************************************************************************/ int rdpup_draw_line(short x1, short y1, short x2, short y2) { - if (g_connected) - { - LLOGLN(10, (" rdpup_draw_line")); - rdpup_pre_check(12); - out_uint16_le(g_out_s, 18); /* draw line */ - out_uint16_le(g_out_s, 12); /* size */ - g_count++; - out_uint16_le(g_out_s, x1); - out_uint16_le(g_out_s, y1); - out_uint16_le(g_out_s, x2); - out_uint16_le(g_out_s, y2); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_draw_line")); + rdpup_pre_check(12); + out_uint16_le(g_out_s, 18); /* draw line */ + out_uint16_le(g_out_s, 12); /* size */ + g_count++; + out_uint16_le(g_out_s, x1); + out_uint16_le(g_out_s, y1); + out_uint16_le(g_out_s, x2); + out_uint16_le(g_out_s, y2); + } + + return 0; } /******************************************************************************/ int -rdpup_set_cursor(short x, short y, char* cur_data, char* cur_mask) +rdpup_set_cursor(short x, short y, char *cur_data, char *cur_mask) { - int size; + int size; - if (g_connected) - { - LLOGLN(10, (" rdpup_set_cursor")); - size = 8 + 32 * (32 * 3) + 32 * (32 / 8); - rdpup_pre_check(size); - out_uint16_le(g_out_s, 19); /* set cursor */ - out_uint16_le(g_out_s, size); /* size */ - g_count++; - x = MAX(0, x); - x = MIN(31, x); - y = MAX(0, y); - y = MIN(31, y); - out_uint16_le(g_out_s, x); - out_uint16_le(g_out_s, y); - out_uint8a(g_out_s, cur_data, 32 * (32 * 3)); - out_uint8a(g_out_s, cur_mask, 32 * (32 / 8)); - } - return 0; + if (g_connected) + { + LLOGLN(10, (" rdpup_set_cursor")); + size = 8 + 32 * (32 * 3) + 32 * (32 / 8); + rdpup_pre_check(size); + out_uint16_le(g_out_s, 19); /* set cursor */ + out_uint16_le(g_out_s, size); /* size */ + g_count++; + x = MAX(0, x); + x = MIN(31, x); + y = MAX(0, y); + y = MIN(31, y); + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint8a(g_out_s, cur_data, 32 * (32 * 3)); + out_uint8a(g_out_s, cur_mask, 32 * (32 / 8)); + } + + return 0; } /******************************************************************************/ int rdpup_create_os_surface(int rdpindex, int width, int height) { - LLOGLN(10, ("rdpup_create_os_surface:")); - if (g_connected) - { - LLOGLN(10, (" rdpup_create_os_surface width %d height %d", width, height)); - rdpup_pre_check(12); - out_uint16_le(g_out_s, 20); - out_uint16_le(g_out_s, 12); - g_count++; - out_uint32_le(g_out_s, rdpindex); - out_uint16_le(g_out_s, width); - out_uint16_le(g_out_s, height); - } - return 0; + LLOGLN(10, ("rdpup_create_os_surface:")); + + if (g_connected) + { + LLOGLN(10, (" rdpup_create_os_surface width %d height %d", width, height)); + rdpup_pre_check(12); + out_uint16_le(g_out_s, 20); + out_uint16_le(g_out_s, 12); + g_count++; + out_uint32_le(g_out_s, rdpindex); + out_uint16_le(g_out_s, width); + out_uint16_le(g_out_s, height); + } + + return 0; } /******************************************************************************/ int rdpup_switch_os_surface(int rdpindex) { - LLOGLN(10, ("rdpup_switch_os_surface:")); - if (g_connected) - { - if (g_rdpindex == rdpindex) + LLOGLN(10, ("rdpup_switch_os_surface:")); + + if (g_connected) { - return 0; + if (g_rdpindex == rdpindex) + { + return 0; + } + + g_rdpindex = rdpindex; + LLOGLN(10, ("rdpup_switch_os_surface: rdpindex %d", rdpindex)); + /* switch surface */ + rdpup_pre_check(8); + out_uint16_le(g_out_s, 21); + out_uint16_le(g_out_s, 8); + out_uint32_le(g_out_s, rdpindex); + g_count++; } - g_rdpindex = rdpindex; - LLOGLN(10, ("rdpup_switch_os_surface: rdpindex %d", rdpindex)); - /* switch surface */ - rdpup_pre_check(8); - out_uint16_le(g_out_s, 21); - out_uint16_le(g_out_s, 8); - out_uint32_le(g_out_s, rdpindex); - g_count++; - } - return 0; + + return 0; } /******************************************************************************/ int rdpup_delete_os_surface(int rdpindex) { - LLOGLN(10, ("rdpup_delete_os_surface: rdpindex %d", rdpindex)); - if (g_connected) - { LLOGLN(10, ("rdpup_delete_os_surface: rdpindex %d", rdpindex)); - rdpup_pre_check(8); - out_uint16_le(g_out_s, 22); - out_uint16_le(g_out_s, 8); - g_count++; - out_uint32_le(g_out_s, rdpindex); - } - return 0; + + if (g_connected) + { + LLOGLN(10, ("rdpup_delete_os_surface: rdpindex %d", rdpindex)); + rdpup_pre_check(8); + out_uint16_le(g_out_s, 22); + out_uint16_le(g_out_s, 8); + g_count++; + out_uint32_le(g_out_s, rdpindex); + } + + return 0; } /******************************************************************************/ static int -get_single_color(struct image_data* id, int x, int y, int w, int h) +get_single_color(struct image_data *id, int x, int y, int w, int h) { - int rv; - int i; - int j; - int p; - unsigned char* i8; - unsigned short* i16; - unsigned int* i32; + int rv; + int i; + int j; + int p; + unsigned char *i8; + unsigned short *i16; + unsigned int *i32; - p = 0; - rv = -1; - if (g_Bpp == 1) - { - for (i = 0; i < h; i++) + p = 0; + rv = -1; + + if (g_Bpp == 1) { - i8 = (unsigned char*)(id->pixels + - ((y + i) * id->lineBytes) + (x * g_Bpp)); - if (i == 0) - { - p = *i8; - } - for (j = 0; j < w; j++) - { - if (i8[j] != p) + for (i = 0; i < h; i++) { - return -1; + i8 = (unsigned char *)(id->pixels + + ((y + i) * id->lineBytes) + (x * g_Bpp)); + + if (i == 0) + { + p = *i8; + } + + for (j = 0; j < w; j++) + { + if (i8[j] != p) + { + return -1; + } + } } - } + + rv = p; } - rv = p; - } - else if (g_Bpp == 2) - { - for (i = 0; i < h; i++) + else if (g_Bpp == 2) { - i16 = (unsigned short*)(id->pixels + - ((y + i) * id->lineBytes) + (x * g_Bpp)); - if (i == 0) - { - p = *i16; - } - for (j = 0; j < w; j++) - { - if (i16[j] != p) + for (i = 0; i < h; i++) { - return -1; + i16 = (unsigned short *)(id->pixels + + ((y + i) * id->lineBytes) + (x * g_Bpp)); + + if (i == 0) + { + p = *i16; + } + + for (j = 0; j < w; j++) + { + if (i16[j] != p) + { + return -1; + } + } } - } + + rv = p; } - rv = p; - } - else if (g_Bpp == 4) - { - for (i = 0; i < h; i++) + else if (g_Bpp == 4) { - i32 = (unsigned int*)(id->pixels + - ((y + i) * id->lineBytes) + (x * g_Bpp)); - if (i == 0) - { - p = *i32; - } - for (j = 0; j < w; j++) - { - if (i32[j] != p) + for (i = 0; i < h; i++) { - return -1; + i32 = (unsigned int *)(id->pixels + + ((y + i) * id->lineBytes) + (x * g_Bpp)); + + if (i == 0) + { + p = *i32; + } + + for (j = 0; j < w; j++) + { + if (i32[j] != p) + { + return -1; + } + } } - } + + rv = p; } - rv = p; - } - return rv; + + return rv; } /******************************************************************************/ /* split the bitmap up into 64 x 64 pixel areas */ void -rdpup_send_area(struct image_data* id, int x, int y, int w, int h) +rdpup_send_area(struct image_data *id, int x, int y, int w, int h) { - char* s; - int i; - int single_color; - int lx; - int ly; - int lh; - int lw; - int size; - struct image_data lid; + char *s; + int i; + int single_color; + int lx; + int ly; + int lh; + int lw; + int size; + struct image_data lid; - LLOGLN(10, ("rdpup_send_area: id %p x %d y %d w %d h %d", id, x, y, w, h)); - if (id == 0) - { - rdpup_get_screen_image_rect(&lid); - id = &lid; - } + LLOGLN(10, ("rdpup_send_area: id %p x %d y %d w %d h %d", id, x, y, w, h)); - if (x >= id->width) - { - return; - } - if (y >= id->height) - { - return; - } - if (x < 0) - { - w += x; - x = 0; - } - if (y < 0) - { - h += y; - y = 0; - } - if (w <= 0) - { - return; - } - if (h <= 0) - { - return; - } - if (x + w > id->width) - { - w = id->width - x; - } - if (y + h > id->height) - { - h = id->height - y; - } - LLOGLN(10, ("%d", w * h)); - if (g_connected && g_begin) - { - LLOGLN(10, (" rdpup_send_area")); - ly = y; - while (ly < y + h) + if (id == 0) { - lx = x; - while (lx < x + w) - { - lw = MIN(64, (x + w) - lx); - lh = MIN(64, (y + h) - ly); - single_color = get_single_color(id, lx, ly, lw, lh); - if (single_color != -1) - { - LLOGLN(10, ("%d sending single color", g_count)); - rdpup_set_fgcolor(single_color); - rdpup_fill_rect(lx, ly, lw, lh); - } - else - { - size = lw * lh * id->Bpp + 24; - rdpup_pre_check(size); - out_uint16_le(g_out_s, 5); - out_uint16_le(g_out_s, size); - g_count++; - out_uint16_le(g_out_s, lx); - out_uint16_le(g_out_s, ly); - out_uint16_le(g_out_s, lw); - out_uint16_le(g_out_s, lh); - out_uint32_le(g_out_s, lw * lh * id->Bpp); - for (i = 0; i < lh; i++) - { - s = (id->pixels + - ((ly + i) * id->lineBytes) + (lx * g_Bpp)); - convert_pixels(s, g_out_s->p, lw); - g_out_s->p += lw * id->Bpp; - } - out_uint16_le(g_out_s, lw); - out_uint16_le(g_out_s, lh); - out_uint16_le(g_out_s, 0); - out_uint16_le(g_out_s, 0); - } - lx += 64; - } - ly += 64; + rdpup_get_screen_image_rect(&lid); + id = &lid; + } + + if (x >= id->width) + { + return; + } + + if (y >= id->height) + { + return; + } + + if (x < 0) + { + w += x; + x = 0; + } + + if (y < 0) + { + h += y; + y = 0; + } + + if (w <= 0) + { + return; + } + + if (h <= 0) + { + return; + } + + if (x + w > id->width) + { + w = id->width - x; + } + + if (y + h > id->height) + { + h = id->height - y; + } + + LLOGLN(10, ("%d", w * h)); + + if (g_connected && g_begin) + { + LLOGLN(10, (" rdpup_send_area")); + ly = y; + + while (ly < y + h) + { + lx = x; + + while (lx < x + w) + { + lw = MIN(64, (x + w) - lx); + lh = MIN(64, (y + h) - ly); + single_color = get_single_color(id, lx, ly, lw, lh); + + if (single_color != -1) + { + LLOGLN(10, ("%d sending single color", g_count)); + rdpup_set_fgcolor(single_color); + rdpup_fill_rect(lx, ly, lw, lh); + } + else + { + size = lw * lh * id->Bpp + 24; + rdpup_pre_check(size); + out_uint16_le(g_out_s, 5); + out_uint16_le(g_out_s, size); + g_count++; + out_uint16_le(g_out_s, lx); + out_uint16_le(g_out_s, ly); + out_uint16_le(g_out_s, lw); + out_uint16_le(g_out_s, lh); + out_uint32_le(g_out_s, lw * lh * id->Bpp); + + for (i = 0; i < lh; i++) + { + s = (id->pixels + + ((ly + i) * id->lineBytes) + (lx * g_Bpp)); + convert_pixels(s, g_out_s->p, lw); + g_out_s->p += lw * id->Bpp; + } + + out_uint16_le(g_out_s, lw); + out_uint16_le(g_out_s, lh); + out_uint16_le(g_out_s, 0); + out_uint16_le(g_out_s, 0); + } + + lx += 64; + } + + ly += 64; + } } - } } /******************************************************************************/ @@ -1444,262 +1575,283 @@ void rdpup_paint_rect_os(int x, int y, int cx, int cy, int rdpindex, int srcx, int srcy) { - if (g_connected) - { - rdpup_pre_check(20); - out_uint16_le(g_out_s, 23); - out_uint16_le(g_out_s, 20); - g_count++; - out_uint16_le(g_out_s, x); - out_uint16_le(g_out_s, y); - out_uint16_le(g_out_s, cx); - out_uint16_le(g_out_s, cy); - out_uint32_le(g_out_s, rdpindex); - out_uint16_le(g_out_s, srcx); - out_uint16_le(g_out_s, srcy); - } + if (g_connected) + { + rdpup_pre_check(20); + out_uint16_le(g_out_s, 23); + out_uint16_le(g_out_s, 20); + g_count++; + out_uint16_le(g_out_s, x); + out_uint16_le(g_out_s, y); + out_uint16_le(g_out_s, cx); + out_uint16_le(g_out_s, cy); + out_uint32_le(g_out_s, rdpindex); + out_uint16_le(g_out_s, srcx); + out_uint16_le(g_out_s, srcy); + } } /******************************************************************************/ void rdpup_set_hints(int hints, int mask) { - if (g_connected) - { - rdpup_pre_check(12); - out_uint16_le(g_out_s, 24); - out_uint16_le(g_out_s, 12); - g_count++; - out_uint32_le(g_out_s, hints); - out_uint32_le(g_out_s, mask); - } + if (g_connected) + { + rdpup_pre_check(12); + out_uint16_le(g_out_s, 24); + out_uint16_le(g_out_s, 12); + g_count++; + out_uint32_le(g_out_s, hints); + out_uint32_le(g_out_s, mask); + } } /******************************************************************************/ void -rdpup_create_window(WindowPtr pWindow, rdpWindowRec* priv) +rdpup_create_window(WindowPtr pWindow, rdpWindowRec *priv) { - int bytes; - int index; - int flags; - int num_window_rects; - int num_visibility_rects; - int title_bytes; - int style; - int ext_style; - int root_id; - char title[256]; + int bytes; + int index; + int flags; + int num_window_rects; + int num_visibility_rects; + int title_bytes; + int style; + int ext_style; + int root_id; + char title[256]; - LLOGLN(10, ("rdpup_create_window: id 0x%8.8x", pWindow->drawable.id)); - if (g_connected) - { - root_id = pWindow->drawable.pScreen->root->drawable.id; + LLOGLN(10, ("rdpup_create_window: id 0x%8.8x", pWindow->drawable.id)); - if (pWindow->overrideRedirect) + if (g_connected) { - style = XR_STYLE_TOOLTIP; - ext_style = XR_EXT_STYLE_TOOLTIP; + root_id = pWindow->drawable.pScreen->root->drawable.id; + + if (pWindow->overrideRedirect) + { + style = XR_STYLE_TOOLTIP; + ext_style = XR_EXT_STYLE_TOOLTIP; + } + else + { + style = XR_STYLE_NORMAL; + ext_style = XR_EXT_STYLE_NORMAL; + } + + flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_STATE_NEW; + strcpy(title, "title"); + title_bytes = strlen(title); + + num_window_rects = 1; + num_visibility_rects = 1; + + /* calculate bytes */ + bytes = (2 + 2) + (5 * 4) + (2 + title_bytes) + (12 * 4) + + (2 + num_window_rects * 8) + (4 + 4) + + (2 + num_visibility_rects * 8) + 4; + + rdpup_pre_check(bytes); + out_uint16_le(g_out_s, 25); + out_uint16_le(g_out_s, bytes); + g_count++; + out_uint32_le(g_out_s, pWindow->drawable.id); /* window_id */ + out_uint32_le(g_out_s, pWindow->parent->drawable.id); /* owner_window_id */ + flags |= WINDOW_ORDER_FIELD_OWNER; + out_uint32_le(g_out_s, style); /* style */ + out_uint32_le(g_out_s, ext_style); /* extended_style */ + flags |= WINDOW_ORDER_FIELD_STYLE; + out_uint32_le(g_out_s, 0); /* show_state */ + flags |= WINDOW_ORDER_FIELD_SHOW; + out_uint16_le(g_out_s, title_bytes); /* title_info */ + out_uint8a(g_out_s, title, title_bytes); + flags |= WINDOW_ORDER_FIELD_TITLE; + out_uint32_le(g_out_s, 0); /* client_offset_x */ + out_uint32_le(g_out_s, 0); /* client_offset_y */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; + out_uint32_le(g_out_s, pWindow->drawable.width); /* client_area_width */ + out_uint32_le(g_out_s, pWindow->drawable.height); /* client_area_height */ + flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; + out_uint32_le(g_out_s, 0); /* rp_content */ + out_uint32_le(g_out_s, root_id); /* root_parent_handle */ + flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; + out_uint32_le(g_out_s, pWindow->drawable.x); /* window_offset_x */ + out_uint32_le(g_out_s, pWindow->drawable.y); /* window_offset_y */ + flags |= WINDOW_ORDER_FIELD_WND_OFFSET; + out_uint32_le(g_out_s, 0); /* window_client_delta_x */ + out_uint32_le(g_out_s, 0); /* window_client_delta_y */ + flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; + out_uint32_le(g_out_s, pWindow->drawable.width); /* window_width */ + out_uint32_le(g_out_s, pWindow->drawable.height); /* window_height */ + flags |= WINDOW_ORDER_FIELD_WND_SIZE; + out_uint16_le(g_out_s, num_window_rects); /* num_window_rects */ + + for (index = 0; index < num_window_rects; index++) + { + out_uint16_le(g_out_s, 0); /* left */ + out_uint16_le(g_out_s, 0); /* top */ + out_uint16_le(g_out_s, pWindow->drawable.width); /* right */ + out_uint16_le(g_out_s, pWindow->drawable.height); /* bottom */ + } + + flags |= WINDOW_ORDER_FIELD_WND_RECTS; + out_uint32_le(g_out_s, 0); /* visible_offset_x */ + out_uint32_le(g_out_s, 0); /* visible_offset_y */ + flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; + out_uint16_le(g_out_s, num_visibility_rects); /* num_visibility_rects */ + + for (index = 0; index < num_visibility_rects; index++) + { + out_uint16_le(g_out_s, 0); /* left */ + out_uint16_le(g_out_s, 0); /* top */ + out_uint16_le(g_out_s, pWindow->drawable.width); /* right */ + out_uint16_le(g_out_s, pWindow->drawable.height); /* bottom */ + } + + flags |= WINDOW_ORDER_FIELD_VISIBILITY; + + out_uint32_le(g_out_s, flags); /* flags */ } - else - { - style = XR_STYLE_NORMAL; - ext_style = XR_EXT_STYLE_NORMAL; - } - - flags = WINDOW_ORDER_TYPE_WINDOW | WINDOW_ORDER_STATE_NEW; - strcpy(title, "title"); - title_bytes = strlen(title); - - num_window_rects = 1; - num_visibility_rects = 1; - - /* calculate bytes */ - bytes = (2 + 2) + (5 * 4) + (2 + title_bytes) + (12 * 4) + - (2 + num_window_rects * 8) + (4 + 4) + - (2 + num_visibility_rects * 8) + 4; - - rdpup_pre_check(bytes); - out_uint16_le(g_out_s, 25); - out_uint16_le(g_out_s, bytes); - g_count++; - out_uint32_le(g_out_s, pWindow->drawable.id); /* window_id */ - out_uint32_le(g_out_s, pWindow->parent->drawable.id); /* owner_window_id */ - flags |= WINDOW_ORDER_FIELD_OWNER; - out_uint32_le(g_out_s, style); /* style */ - out_uint32_le(g_out_s, ext_style); /* extended_style */ - flags |= WINDOW_ORDER_FIELD_STYLE; - out_uint32_le(g_out_s, 0); /* show_state */ - flags |= WINDOW_ORDER_FIELD_SHOW; - out_uint16_le(g_out_s, title_bytes); /* title_info */ - out_uint8a(g_out_s, title, title_bytes); - flags |= WINDOW_ORDER_FIELD_TITLE; - out_uint32_le(g_out_s, 0); /* client_offset_x */ - out_uint32_le(g_out_s, 0); /* client_offset_y */ - flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET; - out_uint32_le(g_out_s, pWindow->drawable.width); /* client_area_width */ - out_uint32_le(g_out_s, pWindow->drawable.height); /* client_area_height */ - flags |= WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE; - out_uint32_le(g_out_s, 0); /* rp_content */ - out_uint32_le(g_out_s, root_id); /* root_parent_handle */ - flags |= WINDOW_ORDER_FIELD_ROOT_PARENT; - out_uint32_le(g_out_s, pWindow->drawable.x); /* window_offset_x */ - out_uint32_le(g_out_s, pWindow->drawable.y); /* window_offset_y */ - flags |= WINDOW_ORDER_FIELD_WND_OFFSET; - out_uint32_le(g_out_s, 0); /* window_client_delta_x */ - out_uint32_le(g_out_s, 0); /* window_client_delta_y */ - flags |= WINDOW_ORDER_FIELD_WND_CLIENT_DELTA; - out_uint32_le(g_out_s, pWindow->drawable.width); /* window_width */ - out_uint32_le(g_out_s, pWindow->drawable.height); /* window_height */ - flags |= WINDOW_ORDER_FIELD_WND_SIZE; - out_uint16_le(g_out_s, num_window_rects); /* num_window_rects */ - for (index = 0; index < num_window_rects; index++) - { - out_uint16_le(g_out_s, 0); /* left */ - out_uint16_le(g_out_s, 0); /* top */ - out_uint16_le(g_out_s, pWindow->drawable.width); /* right */ - out_uint16_le(g_out_s, pWindow->drawable.height); /* bottom */ - } - flags |= WINDOW_ORDER_FIELD_WND_RECTS; - out_uint32_le(g_out_s, 0); /* visible_offset_x */ - out_uint32_le(g_out_s, 0); /* visible_offset_y */ - flags |= WINDOW_ORDER_FIELD_VIS_OFFSET; - out_uint16_le(g_out_s, num_visibility_rects); /* num_visibility_rects */ - for (index = 0; index < num_visibility_rects; index++) - { - out_uint16_le(g_out_s, 0); /* left */ - out_uint16_le(g_out_s, 0); /* top */ - out_uint16_le(g_out_s, pWindow->drawable.width); /* right */ - out_uint16_le(g_out_s, pWindow->drawable.height); /* bottom */ - } - flags |= WINDOW_ORDER_FIELD_VISIBILITY; - - out_uint32_le(g_out_s, flags); /* flags */ - } } /******************************************************************************/ void -rdpup_delete_window(WindowPtr pWindow, rdpWindowRec* priv) +rdpup_delete_window(WindowPtr pWindow, rdpWindowRec *priv) { - LLOGLN(10, ("rdpup_delete_window: id 0x%8.8x", pWindow->drawable.id)); - if (g_connected) - { - rdpup_pre_check(8); - out_uint16_le(g_out_s, 26); - out_uint16_le(g_out_s, 8); - g_count++; - out_uint32_le(g_out_s, pWindow->drawable.id); /* window_id */ - } + LLOGLN(10, ("rdpup_delete_window: id 0x%8.8x", pWindow->drawable.id)); + + if (g_connected) + { + rdpup_pre_check(8); + out_uint16_le(g_out_s, 26); + out_uint16_le(g_out_s, 8); + g_count++; + out_uint32_le(g_out_s, pWindow->drawable.id); /* window_id */ + } } /******************************************************************************/ int -rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec* pDirtyPriv) +rdpup_check_dirty(PixmapPtr pDirtyPixmap, rdpPixmapRec *pDirtyPriv) { - int index; - int clip_index; - int count; - int num_clips; - BoxRec box; - xSegment* seg; - struct image_data id; - struct rdp_draw_item* di; + int index; + int clip_index; + int count; + int num_clips; + BoxRec box; + xSegment *seg; + struct image_data id; + struct rdp_draw_item *di; - if (pDirtyPriv == 0) - { - return 0; - } - if (pDirtyPriv->is_dirty == 0) - { - return 0; - } - - /* update use time / count */ - g_os_bitmaps[pDirtyPriv->rdpindex].stamp = g_os_bitmap_stamp; - g_os_bitmap_stamp++; - - LLOGLN(10, ("-----------------got dirty")); - rdpup_switch_os_surface(pDirtyPriv->rdpindex); - rdpup_get_pixmap_image_rect(pDirtyPixmap, &id); - rdpup_begin_update(); - draw_item_pack(pDirtyPriv); - di = pDirtyPriv->draw_item_head; - while (di != 0) - { - LLOGLN(10, ("rdpup_check_dirty: type %d", di->type)); - switch (di->type) + if (pDirtyPriv == 0) { - case RDI_FILL: - rdpup_set_fgcolor(di->u.fill.fg_color); - rdpup_set_opcode(di->u.fill.opcode); - count = REGION_NUM_RECTS(di->reg); - for (index = 0; index < count; index++) - { - box = REGION_RECTS(di->reg)[index]; - LLOGLN(10, (" RDI_FILL %d %d %d %d", box.x1, box.y1, - box.x2, box.y2)); - rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - rdpup_set_opcode(GXcopy); - break; - case RDI_IMGLL: - rdpup_set_hints(1, 1); - rdpup_set_opcode(di->u.img.opcode); - count = REGION_NUM_RECTS(di->reg); - for (index = 0; index < count; index++) - { - box = REGION_RECTS(di->reg)[index]; - LLOGLN(10, (" RDI_IMGLL %d %d %d %d", box.x1, box.y1, - box.x2, box.y2)); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); - } - rdpup_set_opcode(GXcopy); - rdpup_set_hints(0, 1); - break; - case RDI_IMGLY: - rdpup_set_opcode(di->u.img.opcode); - count = REGION_NUM_RECTS(di->reg); - for (index = 0; index < count; index++) - { - box = REGION_RECTS(di->reg)[index]; - LLOGLN(10, (" RDI_IMGLY %d %d %d %d", box.x1, box.y1, - box.x2, box.y2)); - rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, - box.y2 - box.y1); - } - rdpup_set_opcode(GXcopy); - break; - case RDI_LINE: - LLOGLN(10, (" RDI_LINE")); - num_clips = REGION_NUM_RECTS(di->reg); - if (num_clips > 0) - { - rdpup_set_fgcolor(di->u.line.fg_color); - rdpup_set_opcode(di->u.line.opcode); - rdpup_set_pen(0, di->u.line.width); - for (clip_index = num_clips - 1; clip_index >= 0; clip_index--) - { - box = REGION_RECTS(di->reg)[clip_index]; - rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - for (index = 0; index < di->u.line.nseg; index++) - { - seg = di->u.line.segs + index; - LLOGLN(10, (" RDI_LINE %d %d %d %d", seg->x1, seg->y1, - seg->x2, seg->y2)); - rdpup_draw_line(seg->x1, seg->y1, seg->x2, seg->y2); - } - } - } - rdpup_reset_clip(); - rdpup_set_opcode(GXcopy); - break; + return 0; } - di = di->next; - } - draw_item_remove_all(pDirtyPriv); - rdpup_end_update(); - pDirtyPriv->is_dirty = 0; - rdpup_switch_os_surface(-1); - return 0; + + if (pDirtyPriv->is_dirty == 0) + { + return 0; + } + + /* update use time / count */ + g_os_bitmaps[pDirtyPriv->rdpindex].stamp = g_os_bitmap_stamp; + g_os_bitmap_stamp++; + + LLOGLN(10, ("-----------------got dirty")); + rdpup_switch_os_surface(pDirtyPriv->rdpindex); + rdpup_get_pixmap_image_rect(pDirtyPixmap, &id); + rdpup_begin_update(); + draw_item_pack(pDirtyPriv); + di = pDirtyPriv->draw_item_head; + + while (di != 0) + { + LLOGLN(10, ("rdpup_check_dirty: type %d", di->type)); + + switch (di->type) + { + case RDI_FILL: + rdpup_set_fgcolor(di->u.fill.fg_color); + rdpup_set_opcode(di->u.fill.opcode); + count = REGION_NUM_RECTS(di->reg); + + for (index = 0; index < count; index++) + { + box = REGION_RECTS(di->reg)[index]; + LLOGLN(10, (" RDI_FILL %d %d %d %d", box.x1, box.y1, + box.x2, box.y2)); + rdpup_fill_rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } + + rdpup_set_opcode(GXcopy); + break; + case RDI_IMGLL: + rdpup_set_hints(1, 1); + rdpup_set_opcode(di->u.img.opcode); + count = REGION_NUM_RECTS(di->reg); + + for (index = 0; index < count; index++) + { + box = REGION_RECTS(di->reg)[index]; + LLOGLN(10, (" RDI_IMGLL %d %d %d %d", box.x1, box.y1, + box.x2, box.y2)); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_set_opcode(GXcopy); + rdpup_set_hints(0, 1); + break; + case RDI_IMGLY: + rdpup_set_opcode(di->u.img.opcode); + count = REGION_NUM_RECTS(di->reg); + + for (index = 0; index < count; index++) + { + box = REGION_RECTS(di->reg)[index]; + LLOGLN(10, (" RDI_IMGLY %d %d %d %d", box.x1, box.y1, + box.x2, box.y2)); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, + box.y2 - box.y1); + } + + rdpup_set_opcode(GXcopy); + break; + case RDI_LINE: + LLOGLN(10, (" RDI_LINE")); + num_clips = REGION_NUM_RECTS(di->reg); + + if (num_clips > 0) + { + rdpup_set_fgcolor(di->u.line.fg_color); + rdpup_set_opcode(di->u.line.opcode); + rdpup_set_pen(0, di->u.line.width); + + for (clip_index = num_clips - 1; clip_index >= 0; clip_index--) + { + box = REGION_RECTS(di->reg)[clip_index]; + rdpup_set_clip(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + + for (index = 0; index < di->u.line.nseg; index++) + { + seg = di->u.line.segs + index; + LLOGLN(10, (" RDI_LINE %d %d %d %d", seg->x1, seg->y1, + seg->x2, seg->y2)); + rdpup_draw_line(seg->x1, seg->y1, seg->x2, seg->y2); + } + } + } + + rdpup_reset_clip(); + rdpup_set_opcode(GXcopy); + break; + } + + di = di->next; + } + + draw_item_remove_all(pDirtyPriv); + rdpup_end_update(); + pDirtyPriv->is_dirty = 0; + rdpup_switch_os_surface(-1); + return 0; } diff --git a/xorg/tests/client.sh b/xorg/tests/nx/client.sh similarity index 100% rename from xorg/tests/client.sh rename to xorg/tests/nx/client.sh diff --git a/xorg/tests/server.sh b/xorg/tests/nx/server.sh similarity index 100% rename from xorg/tests/server.sh rename to xorg/tests/nx/server.sh diff --git a/xorg/tests/tcp_proxy/Makefile b/xorg/tests/tcp_proxy/Makefile deleted file mode 100644 index eeb33711..00000000 --- a/xorg/tests/tcp_proxy/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -XRDP_INSTALL_BASE=/home/jay/xrdpinst - -OBJS = main.o -CFLAGS = -O2 -Wall -I../../../common -LDFLAGS = -Wl,-rpath,$(XRDP_INSTALL_BASE)/lib/xrdp -LIBS = -L$(XRDP_INSTALL_BASE)/lib/xrdp -ldl -lcommon - -all: tcp_proxy - -tcp_proxy: $(OBJS) - $(CC) $(CFLAGS) $(LDFLAGS) -o tcp_proxy $(OBJS) $(LIBS) - -clean: - rm -f $(OBJS) tcp_proxy diff --git a/xorg/tests/tcp_proxy/main.c b/xorg/tests/tcp_proxy/main.c deleted file mode 100644 index 0e6f4fe3..00000000 --- a/xorg/tests/tcp_proxy/main.c +++ /dev/null @@ -1,265 +0,0 @@ - -#include "os_calls.h" - -int g_loc_io_count = 0; // bytes read from local port -int g_rem_io_count = 0; // bytes read from remote port - -static int g_terminated = 0; -static char g_buf[1024 * 32]; - -/*****************************************************************************/ -static int -main_loop(char* local_port, char* remote_ip, char* remote_port, int hexdump) -{ - int lis_sck; - int acc_sck; - int con_sck; - int sel; - int count; - int sent; - int error; - int i; - int acc_to_con; - int con_to_acc; - - acc_to_con = 0; - con_to_acc = 0; - acc_sck = 0; - - /* create the listening socket and setup options */ - lis_sck = g_tcp_socket(); - g_tcp_set_non_blocking(lis_sck); - error = g_tcp_bind(lis_sck, local_port); - if (error != 0) - { - g_writeln("bind failed"); - } - - /* listen for an incomming connection */ - if (error == 0) - { - error = g_tcp_listen(lis_sck); - if (error == 0) - { - g_writeln("listening for connection"); - } - } - - /* accept an incomming connection */ - if (error == 0) - { - while ((!g_terminated) && (error == 0)) - { - acc_sck = g_tcp_accept(lis_sck); - if ((acc_sck == -1) && g_tcp_last_error_would_block(lis_sck)) - { - g_sleep(100); - } - else if (acc_sck == -1) - { - error = 1; - } - else - { - break; - } - } - if (error == 0) - { - error = g_terminated; - } - - /* stop listening */ - g_tcp_close(lis_sck); - lis_sck = 0; - if (error == 0) - { - g_writeln("got connection"); - } - } - - /* connect outgoing socket */ - con_sck = 0; - if (error == 0) - { - con_sck = g_tcp_socket(); - g_tcp_set_non_blocking(con_sck); - error = g_tcp_connect(con_sck, remote_ip, remote_port); - if ((error == -1) && g_tcp_last_error_would_block(con_sck)) - { - error = 0; - i = 0; - while ((!g_tcp_can_send(con_sck, 100)) && (!g_terminated) && (i < 100)) - { - g_sleep(100); - i++; - } - if (i > 99) - { - g_writeln("timout connecting"); - error = 1; - } - if (g_terminated) - { - error = 1; - } - } - if ((error != 0) && (!g_terminated)) - { - g_writeln("error connecting to remote\r\n"); - } - } - while ((!g_terminated) && (error == 0)) - { - sel = g_tcp_select(con_sck, acc_sck); - if (sel == 0) - { - g_sleep(10); - continue; - } - if (sel & 1) - { - // can read from con_sck w/o blocking - count = g_tcp_recv(con_sck, g_buf, 1024 * 16, 0); - error = count < 1; - if (error == 0) - { - g_loc_io_count += count; - con_to_acc += count; - if (hexdump) - { - g_writeln("from remove, the socket from connect"); - g_hexdump(g_buf, count); - } -#if 0 - g_writeln("local_io_count: %d\tremote_io_count: %d", - g_loc_io_count, g_rem_io_count); -#endif - sent = 0; - while ((sent < count) && (error == 0) && (!g_terminated)) - { - i = g_tcp_send(acc_sck, g_buf + sent, count - sent, 0); - if ((i == -1) && g_tcp_last_error_would_block(acc_sck)) - { - g_tcp_can_send(acc_sck, 1000); - } - else if (i < 1) - { - error = 1; - } - else - { - sent += i; - } - } - } - } - if (sel & 2) - { - // can read from acc_sck w/o blocking - count = g_tcp_recv(acc_sck, g_buf, 1024 * 16, 0); - error = count < 1; - if (error == 0) - { - g_rem_io_count += count; - acc_to_con += count; - if (hexdump) - { - g_writeln("from accepted, the socket from accept"); - g_hexdump(g_buf, count); - } -#if 0 - g_writeln("local_io_count: %d\tremote_io_count: %d", - g_loc_io_count, g_rem_io_count); -#endif - sent = 0; - while ((sent < count) && (error == 0) && (!g_terminated)) - { - i = g_tcp_send(con_sck, g_buf + sent, count - sent, 0); - if ((i == -1) && g_tcp_last_error_would_block(con_sck)) - { - g_tcp_can_send(con_sck, 1000); - } - else if (i < 1) - { - error = 1; - } - else - { - sent += i; - } - } - } - } - } - g_tcp_close(lis_sck); - g_tcp_close(con_sck); - g_tcp_close(acc_sck); - g_writeln("acc_to_con %d", acc_to_con); - g_writeln("con_to_acc %d", con_to_acc); - return 0; -} - - -/*****************************************************************************/ -static int -usage(void) -{ - g_writeln("tcp_proxy [dump]"); - return 0; -} - - -/*****************************************************************************/ -void -proxy_shutdown(int sig) -{ - g_writeln("shutting down"); - g_terminated = 1; -} - -void -clear_counters(int sig) -{ - g_writeln("cleared counters at: local_io_count: %d remote_io_count: %d", - g_loc_io_count, g_rem_io_count); - g_loc_io_count = 0; - g_rem_io_count = 0; -} - -/*****************************************************************************/ -int -main(int argc, char** argv) -{ - int dump; - - if (argc < 4) - { - usage(); - return 0; - } - g_init("tcp_proxy"); - g_signal_user_interrupt(proxy_shutdown); /* SIGINT */ - g_signal_kill(proxy_shutdown); /* SIGKILL */ - g_signal_usr1(clear_counters); /* SIGUSR1*/ - g_signal_terminate(proxy_shutdown); /* SIGTERM */ - if (argc < 5) - { - while (!g_terminated) - { - g_loc_io_count = 0; - g_rem_io_count = 0; - main_loop(argv[1], argv[2], argv[3], 0); - } - } - else - { - dump = g_strcasecmp(argv[4], "dump") == 0; - while (!g_terminated) - { - main_loop(argv[1], argv[2], argv[3], dump); - } - } - g_deinit(); - return 0; -} diff --git a/xorg/tests/xdemo/README.txt b/xorg/tests/xdemo/README.txt index 52bda08c..2bb59358 100644 --- a/xorg/tests/xdemo/README.txt +++ b/xorg/tests/xdemo/README.txt @@ -1,3 +1,3 @@ -this is a project to develope a program to test xwindows +this is a program to test xwindows diff --git a/xorg/tests/xdemo/bmp_parser.c b/xorg/tests/xdemo/bmp_parser.c index 9d3e43c8..66c050d8 100644 --- a/xorg/tests/xdemo/bmp_parser.c +++ b/xorg/tests/xdemo/bmp_parser.c @@ -1,3 +1,21 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include #include #include @@ -50,13 +68,15 @@ int parse_bmp(char *filename, struct pic_info *pic_info) struct bmp_hdr bmp_hdr; struct dib_hdr dib_hdr; - if ((fd = open(filename, O_RDONLY)) < 0) { + if ((fd = open(filename, O_RDONLY)) < 0) + { printf("error opeing %s\n", filename); return -1; } // read BMP magic... - if ((rval = read(fd, magic.magic, 2)) != 2) { + if ((rval = read(fd, magic.magic, 2)) != 2) + { fprintf(stderr, "error reading BMP signature from file %s\n", filename); return -1; } @@ -64,44 +84,53 @@ int parse_bmp(char *filename, struct pic_info *pic_info) got_magic = 0; // ...and confirm that this is indeed a BMP file - if ((magic.magic[0] == 'B') && (magic.magic[1] == 'M')) { + if ((magic.magic[0] == 'B') && (magic.magic[1] == 'M')) + { // BM – Windows 3.1x, 95, NT, ... etc got_magic = 1; } - else if ((magic.magic[0] == 'B') && (magic.magic[1] == 'A')) { + else if ((magic.magic[0] == 'B') && (magic.magic[1] == 'A')) + { // BA – OS/2 struct Bitmap Array got_magic = 1; } - else if ((magic.magic[0] == 'C') && (magic.magic[1] == 'I')) { + else if ((magic.magic[0] == 'C') && (magic.magic[1] == 'I')) + { // CI – OS/2 struct Color Icon got_magic = 1; } - else if ((magic.magic[0] == 'C') && (magic.magic[1] == 'P')) { + else if ((magic.magic[0] == 'C') && (magic.magic[1] == 'P')) + { // CP – OS/2 const Color Pointer got_magic = 1; } - else if ((magic.magic[0] == 'I') && (magic.magic[1] == 'C')) { + else if ((magic.magic[0] == 'I') && (magic.magic[1] == 'C')) + { // IC – OS/2 struct Icon got_magic = 1; } - else if ((magic.magic[0] == 'P') && (magic.magic[1] == 'T')) { + else if ((magic.magic[0] == 'P') && (magic.magic[1] == 'T')) + { // PT – OS/2 Pointer got_magic = 1; } - if (!got_magic) { + if (!got_magic) + { fprintf(stderr, "%s is not a valid BMP file\n", filename); return -1; } // read BMP header - if ((rval = read(fd, &bmp_hdr, sizeof(bmp_hdr))) < sizeof(bmp_hdr)) { + if ((rval = read(fd, &bmp_hdr, sizeof(bmp_hdr))) < sizeof(bmp_hdr)) + { fprintf(stderr, "error BMP header from file %s\n", filename); return -1; } // read DIB header - if ((rval = read(fd, &dib_hdr, sizeof(dib_hdr))) < sizeof(dib_hdr)) { + if ((rval = read(fd, &dib_hdr, sizeof(dib_hdr))) < sizeof(dib_hdr)) + { fprintf(stderr, "error reading DIB header from file %s\n", filename); return -1; } @@ -120,7 +149,8 @@ int parse_bmp(char *filename, struct pic_info *pic_info) printf("nimpcolors: %d\n", dib_hdr.nimpcolors); #endif - if (dib_hdr.compress_type) { + if (dib_hdr.compress_type) + { printf("TODO: compressed images not yet supported\n"); return -1; } @@ -128,9 +158,11 @@ int parse_bmp(char *filename, struct pic_info *pic_info) pic_info->width = dib_hdr.width; pic_info->height = dib_hdr.height; - if (dib_hdr.bpp == 24) { + if (dib_hdr.bpp == 24) + { rval = parse_bmp_24(&bmp_hdr, &dib_hdr, fd, pic_info); } + close(fd); return rval; } @@ -189,6 +221,7 @@ int parse_bmp_24( for (i = 0; i < h; i ++) { cptr = ptr_file_data; + for (j = 0; j < w; j++) { *ptr_mem_data++ = *cptr++; // blue value @@ -196,6 +229,7 @@ int parse_bmp_24( *ptr_mem_data++ = *cptr++; // red value *ptr_mem_data++ = 0; // alpha channel } + ptr_file_data -= bpl; } diff --git a/xorg/tests/xdemo/common.h b/xorg/tests/xdemo/common.h index 2ce75bba..8ed4ee65 100644 --- a/xorg/tests/xdemo/common.h +++ b/xorg/tests/xdemo/common.h @@ -1,3 +1,21 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #ifndef __XDEMO_H #define __XDEMO_H diff --git a/xorg/tests/xdemo/xdemo.c b/xorg/tests/xdemo/xdemo.c index 01bd248e..f7e6b0ef 100644 --- a/xorg/tests/xdemo/xdemo.c +++ b/xorg/tests/xdemo/xdemo.c @@ -1,3 +1,21 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include #include #include @@ -78,7 +96,8 @@ int drawLines(int count) int i; int index; - if (count <= 0) { + if (count <= 0) + { return 0; // nothing to do } @@ -92,14 +111,18 @@ int drawLines(int count) x2 = random() % g_winWidth; y2 = random() % g_winHeight; XSetForeground(g_disp, g_gc, g_colors[index++].pixel); - if (index == MAX_COLORS) { + + if (index == MAX_COLORS) + { index = 0; } + // from-to XDrawLine(g_disp, g_win, g_gc, x1, y1, x2, y2); XFlush(g_disp); usleep(g_delay_dur); } + return 0; } @@ -114,7 +137,8 @@ int drawRectangles(int count) int i; int index; - if (count <= 0) { + if (count <= 0) + { return 0; // nothing to do } @@ -128,14 +152,18 @@ int drawRectangles(int count) w = 160; h = 140; XSetForeground(g_disp, g_gc, g_colors[index++].pixel); - if (index == MAX_COLORS) { + + if (index == MAX_COLORS) + { index = 0; } + //XDrawRectangle(g_disp, g_win, g_gc, x1, y1, w, h); XFillRectangle(g_disp, g_win, g_gc, x1, y1, w, h); XFlush(g_disp); usleep(g_delay_dur); } + return 0; } @@ -153,7 +181,8 @@ int drawFont(int count, char *msg) char **font_list; #endif - if (count <= 0) { + if (count <= 0) + { return 0; // nothing to do } @@ -162,17 +191,23 @@ int drawFont(int count, char *msg) #ifdef CHANGE_FONT_SIZE font_list = XListFonts(g_disp, "−*−courier−*−*−*−*−0−0−*−*−*−0−*−*", 2000, &actual_count); - if (!font_list) { + + if (!font_list) + { printf("actual_count=%d\n", actual_count); + for (i = 0; i < actual_count; i++) { printf("%s\n", font_list[i]); } + XFreeFontNames(font_list); } - else { + else + { printf("XListFonts() reted NULL\n"); } + #endif srandom(time(NULL)); @@ -182,13 +217,17 @@ int drawFont(int count, char *msg) x1 = random() % g_winWidth; y1 = random() % g_winHeight; XSetForeground(g_disp, g_gc, g_colors[index++].pixel); - if (index == MAX_COLORS) { + + if (index == MAX_COLORS) + { index = 0; } + XDrawString(g_disp, g_win, g_gc, x1, y1, msg, strlen(msg)); XFlush(g_disp); usleep(g_delay_dur); } + return 0; // nothing to do } @@ -244,7 +283,7 @@ usage(void) } int -main(int argc, char** argv) +main(int argc, char **argv) { XEvent evt; Colormap colormap; @@ -286,160 +325,190 @@ main(int argc, char** argv) // process cmd line args opterr = 0; + while ((opt = getopt(argc, argv, "lrsjg:c:f:i:d:o:z:")) != -1) { switch (opt) { - - case 'j': - draw_lines = 0; - draw_rects = 0; - draw_stipples = 0; - draw_fonts = 0; - draw_image = 0; - draw_offscreen = 1; - break; - - case 'g': - if (sscanf(optarg, "%dx%d", &g_winWidth, &g_winHeight) != 2) { - fprintf(stderr, "\nerror: invalid geometry specified\n\n"); + + case 'j': + draw_lines = 0; + draw_rects = 0; + draw_stipples = 0; + draw_fonts = 0; + draw_image = 0; + draw_offscreen = 1; + break; + + case 'g': + + if (sscanf(optarg, "%dx%d", &g_winWidth, &g_winHeight) != 2) + { + fprintf(stderr, "\nerror: invalid geometry specified\n\n"); + usage(); + return -1; + } + + break; + + case 'c': + + if (sscanf(optarg, "%d", &iters) != 1) + { + fprintf(stderr, "\nerror: invalid count specified\n\n"); + usage(); + return -1; + } + + break; + + case 'l': + draw_lines = 1; + draw_rects = 0; + draw_stipples = 0; + draw_fonts = 0; + draw_image = 0; + draw_offscreen = 0; + break; + + case 'r': + draw_rects = 1; + draw_lines = 0; + draw_stipples = 0; + draw_fonts = 0; + draw_image = 0; + draw_offscreen = 0; + break; + + case 's': + draw_stipples = 1; + draw_lines = 0; + draw_rects = 0; + draw_fonts = 0; + draw_image = 0; + draw_offscreen = 0; + break; + + case 'f': + + if (strlen(optarg) <= 0) + { + fprintf(stderr, "\nerror: -f option requires an argument\n\n"); + usage(); + return -1; + } + + draw_fonts = 1; + strncpy(msg, optarg, 4096); + draw_lines = 0; + draw_rects = 0; + draw_stipples = 0; + draw_image = 0; + draw_offscreen = 0; + break; + + case 'i': + + if (strlen(optarg) <= 0) + { + fprintf(stderr, "\nerror: -i option requires an argument\n\n"); + usage(); + return -1; + } + + draw_image = 1; + strncpy(image_file, optarg, 255); + draw_lines = 0; + draw_rects = 0; + draw_stipples = 0; + draw_fonts = 0; + draw_offscreen = 0; + break; + + case 'h': + usage(); + return 0; + break; + + case 'v': + printf("xdemo Ver 1.0\n"); + return 0; + break; + + case 'd': + + if (sscanf(optarg, "%d", &g_delay_dur) != 1) + { + fprintf(stderr, "\nerror: -d option requires an argument\n\n"); + usage(); + return -1; + } + + break; + + case 'z': + + if (strlen(optarg) <= 0) + { + fprintf(stderr, "\nerror: invalid proxy application specified\n\n"); + usage(); + return -1; + } + + strcpy(proxy_app, optarg); + printf("##### LK_TODO: proxy_app=%s\n", proxy_app); + zero_counters = 1; + break; + + case 'o': + + if (strcmp(optarg, "jump") == 0) + { + scroll_type = SCROLL_JUMP; + } + else if (strcmp(optarg, "smooth1") == 0) + { + scroll_type = SCROLL_SMOOTH1; + } + else if (strcmp(optarg, "smooth2") == 0) + { + scroll_type = SCROLL_SMOOTH2; + } + else if (strcmp(optarg, "smooth3") == 0) + { + scroll_type = SCROLL_SMOOTH3; + } + else if (strcmp(optarg, "smooth4") == 0) + { + scroll_type = SCROLL_SMOOTH4; + } + else + { + fprintf(stderr, "\ninvalid scroll type specified\n\n"); + usage(); + return -1; + } + + break; + + default: usage(); return -1; - } - break; - - case 'c': - if (sscanf(optarg, "%d", &iters) != 1) { - fprintf(stderr, "\nerror: invalid count specified\n\n"); - usage(); - return -1; - } - break; - - case 'l': - draw_lines = 1; - draw_rects = 0; - draw_stipples = 0; - draw_fonts = 0; - draw_image = 0; - draw_offscreen = 0; - break; - - case 'r': - draw_rects = 1; - draw_lines = 0; - draw_stipples = 0; - draw_fonts = 0; - draw_image = 0; - draw_offscreen = 0; - break; - - case 's': - draw_stipples = 1; - draw_lines = 0; - draw_rects = 0; - draw_fonts = 0; - draw_image = 0; - draw_offscreen = 0; - break; - - case 'f': - if (strlen(optarg) <= 0) { - fprintf(stderr, "\nerror: -f option requires an argument\n\n"); - usage(); - return -1; - } - draw_fonts = 1; - strncpy(msg, optarg, 4096); - draw_lines = 0; - draw_rects = 0; - draw_stipples = 0; - draw_image = 0; - draw_offscreen = 0; - break; - - case 'i': - if (strlen(optarg) <= 0) { - fprintf(stderr, "\nerror: -i option requires an argument\n\n"); - usage(); - return -1; - } - draw_image = 1; - strncpy(image_file, optarg, 255); - draw_lines = 0; - draw_rects = 0; - draw_stipples = 0; - draw_fonts = 0; - draw_offscreen= 0; - break; - - case 'h': - usage(); - return 0; - break; - - case 'v': - printf("xdemo Ver 1.0\n"); - return 0; - break; - - case 'd': - if (sscanf(optarg, "%d", &g_delay_dur) != 1) { - fprintf(stderr, "\nerror: -d option requires an argument\n\n"); - usage(); - return -1; - } - break; - - case 'z': - if (strlen(optarg) <= 0) { - fprintf(stderr, "\nerror: invalid proxy application specified\n\n"); - usage(); - return -1; - } - strcpy(proxy_app, optarg); - printf("##### LK_TODO: proxy_app=%s\n", proxy_app); - zero_counters = 1; - break; - - case 'o': - if (strcmp(optarg, "jump") == 0) { - scroll_type = SCROLL_JUMP; - } - else if (strcmp(optarg, "smooth1") == 0) { - scroll_type = SCROLL_SMOOTH1; - } - else if (strcmp(optarg, "smooth2") == 0) { - scroll_type = SCROLL_SMOOTH2; - } - else if (strcmp(optarg, "smooth3") == 0) { - scroll_type = SCROLL_SMOOTH3; - } - else if (strcmp(optarg, "smooth4") == 0) { - scroll_type = SCROLL_SMOOTH4; - } - else { - fprintf(stderr, "\ninvalid scroll type specified\n\n"); - usage(); - return -1; - } - break; - - default: - usage(); - return -1; } } // must have at least one operation if ((!draw_lines) && (!draw_rects) && (!draw_stipples) && - (!draw_fonts) && (!draw_image) && (!draw_offscreen)) { + (!draw_fonts) && (!draw_image) && (!draw_offscreen)) + { usage(); return -1; } g_disp = XOpenDisplay(NULL); - if (!g_disp) { + + if (!g_disp) + { dprint("error opening X display\n"); exit(-1); } @@ -461,88 +530,114 @@ main(int argc, char** argv) XSelectInput(g_disp, g_win, eventMask); g_gc = XCreateGC(g_disp, g_win, - 0, // mask of values - NULL ); // array of values - #if 0 + 0, // mask of values + NULL ); // array of values +#if 0 + do { dprint("about to call XNextEvent(...)\n"); XNextEvent(g_disp, &evt);// calls XFlush dprint("returned from XNextEvent(...)\n"); } + //while(evt.type != MapNotify); - while(evt.type != VisibilityNotify); - #endif + while (evt.type != VisibilityNotify) + { + ; + } + +#endif // get access to the screen's color map colormap = DefaultColormap(g_disp, screenNumber); // alloc red color rc = XAllocNamedColor(g_disp, colormap, "red", &g_colors[0], &g_colors[0]); - if (rc == 0) { + + if (rc == 0) + { printf("XAllocNamedColor - failed to allocated 'red' color.\n"); exit(1); } rc = XAllocNamedColor(g_disp, colormap, "green", &g_colors[1], &g_colors[1]); - if (rc == 0) { + + if (rc == 0) + { printf("XAllocNamedColor - failed to allocated 'green' color.\n"); exit(1); } rc = XAllocNamedColor(g_disp, colormap, "blue", &g_colors[2], &g_colors[2]); - if (rc == 0) { + + if (rc == 0) + { printf("XAllocNamedColor - failed to allocated 'blue' color.\n"); exit(1); } + rc = XAllocNamedColor(g_disp, colormap, "yellow", &g_colors[3], &g_colors[3]); - if (rc == 0) { + + if (rc == 0) + { printf("XAllocNamedColor - failed to allocated 'yellow' color.\n"); exit(1); } + rc = XAllocNamedColor(g_disp, colormap, "orange", &g_colors[4], &g_colors[4]); - if (rc == 0) { + + if (rc == 0) + { printf("XAllocNamedColor - failed to allocated 'orange' color.\n"); exit(1); } - if (zero_counters) { + if (zero_counters) + { signal_tcp_proxy(proxy_app); } - if (draw_lines) { + if (draw_lines) + { start_timer(&tv); drawLines(iters); printf("drew %d lines in %d ms\n", iters, time_elapsed_ms(tv)); } - if (draw_rects) { + if (draw_rects) + { start_timer(&tv); drawRectangles(iters); printf("drew %d rects in %d ms\n", iters, time_elapsed_ms(tv)); } - if (draw_stipples) { + if (draw_stipples) + { start_timer(&tv); // LK_TODO } - if (draw_fonts) { + if (draw_fonts) + { start_timer(&tv); - drawFont(iters, msg); + drawFont(iters, msg); printf("drew %d strings in %d ms\n", iters, time_elapsed_ms(tv)); } - if (draw_image) { + if (draw_image) + { start_timer(&tv); drawBMP(image_file, scroll_type); printf("drew BMP in %d ms\n", time_elapsed_ms(tv)); } - - if (draw_offscreen) { + + if (draw_offscreen) + { } - if (zero_counters) { + if (zero_counters) + { signal_tcp_proxy(proxy_app); } @@ -553,12 +648,15 @@ main(int argc, char** argv) do { XNextEvent(g_disp, &evt); // calls XFlush() - if (evt.type == KeyPress) { - if (draw_offscreen) { + + if (evt.type == KeyPress) + { + if (draw_offscreen) + { drawoffscreen(); } } - + } while (evt.type != ButtonRelease); @@ -578,9 +676,11 @@ int drawBMP(char *filename, int scroll_type) int i; int j; - if (parse_bmp(filename, &pic_info) < 0) { + if (parse_bmp(filename, &pic_info) < 0) + { exit(-1); } + XClearArea(g_disp, g_win, 0, 0, g_winWidth, g_winHeight, 0); depth = DefaultDepth(g_disp, DefaultScreen(g_disp)); @@ -593,7 +693,8 @@ int drawBMP(char *filename, int scroll_type) image = XCreateImage(g_disp, visual, depth, ZPixmap, 0, pic_info.pixel_data, pic_info.width, pic_info.height, 32, 0); - if (pic_info.height <= g_winHeight) { + if (pic_info.height <= g_winHeight) + { // image is too small to scroll XFlush(g_disp); XPutImage(g_disp, g_win, g_gc, image, 0, 0, 0, 0, pic_info.width, pic_info.height); @@ -604,9 +705,11 @@ int drawBMP(char *filename, int scroll_type) // copy image to pixelmap XPutImage(g_disp, pixmap, g_gc, image, 0, 0, 0, 0, pic_info.width, pic_info.height); - if (scroll_type == SCROLL_JUMP) { + if (scroll_type == SCROLL_JUMP) + { - if (pic_info.height <= g_winHeight) { + if (pic_info.height <= g_winHeight) + { // image too small - no scrolling required XFlush(g_disp); XCopyArea(g_disp, // connection to X server @@ -622,11 +725,15 @@ int drawBMP(char *filename, int scroll_type) } j = pic_info.height / g_winHeight; - if (pic_info.height % g_winHeight != 0) { + + if (pic_info.height % g_winHeight != 0) + { // need to include the last part of the image j++; } + XFlush(g_disp); + for (i = 0; i < j; i++) { XCopyArea(g_disp, // connection to X server @@ -649,25 +756,30 @@ int drawBMP(char *filename, int scroll_type) // number of lines to be scrolled j = pic_info.height - g_winHeight; - if (scroll_type == SCROLL_SMOOTH1) { + if (scroll_type == SCROLL_SMOOTH1) + { printf("running SCROLL_SMOOTH1\n"); XFlush(g_disp); XPutImage(g_disp, g_win, g_gc, image, 0, 0, 0, 0, pic_info.width, pic_info.height); XFlush(g_disp); usleep(10000); + for (i = 0; i < j; i++) { XCopyArea(g_disp, g_win, g_win, g_gc, 0, 1, g_winWidth, g_winHeight - 1, 0, 0); - XPutImage(g_disp, g_win, g_gc, image, 0, g_winHeight + i, 0, g_winHeight -1 , pic_info.width, 1); + XPutImage(g_disp, g_win, g_gc, image, 0, g_winHeight + i, 0, g_winHeight - 1 , pic_info.width, 1); XFlush(g_disp); usleep(10000); } + return 0; } - if (scroll_type == SCROLL_SMOOTH2) { + if (scroll_type == SCROLL_SMOOTH2) + { printf("running SCROLL_SMOOTH2\n"); XFlush(g_disp); + for (i = 0; i < j; i++) { XPutImage(g_disp, g_win, g_gc, image, 0, i, 0, 0, pic_info.width, pic_info.height - i); @@ -675,25 +787,31 @@ int drawBMP(char *filename, int scroll_type) usleep(10000); } } - if (scroll_type == SCROLL_SMOOTH3) { + + if (scroll_type == SCROLL_SMOOTH3) + { printf("running SCROLL_SMOOTH3\n"); XFlush(g_disp); XCopyArea(g_disp, pixmap, g_win, g_gc, 0, 0, pic_info.width, pic_info.height, 0, 0); XFlush(g_disp); usleep(10000); + for (i = 0; i < j; i++) { XCopyArea(g_disp, g_win, g_win, g_gc, 0, 1, g_winWidth, g_winHeight - 1, 0, 0); - XCopyArea(g_disp, pixmap, g_win, g_gc, 0, g_winHeight + i, pic_info.width, 1, 0, g_winHeight -1); + XCopyArea(g_disp, pixmap, g_win, g_gc, 0, g_winHeight + i, pic_info.width, 1, 0, g_winHeight - 1); XFlush(g_disp); usleep(10000); } + return 0; } - if (scroll_type == SCROLL_SMOOTH4) { + if (scroll_type == SCROLL_SMOOTH4) + { printf("running SCROLL_SMOOTH4\n"); XFlush(g_disp); + for (i = 0; i < j; i++) { XCopyArea(g_disp, pixmap, g_win, g_gc, 0, i, pic_info.width, pic_info.height - i, 0, 0); @@ -710,19 +828,21 @@ int process_bmp_event() XEvent ev; long event_mask; - event_mask = ExposureMask|ButtonPressMask|ButtonReleaseMask|StructureNotifyMask; + event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask; XSelectInput(g_disp, g_win, event_mask); XNextEvent(g_disp, &ev); - switch(ev.type) - { - case Expose: - printf("got expose event\n"); - break; - default: - printf("did not get expose event\n"); - break; + switch (ev.type) + { + case Expose: + printf("got expose event\n"); + break; + + default: + printf("did not get expose event\n"); + break; } + return 0; } @@ -743,22 +863,29 @@ int signal_tcp_proxy(char *proc_name) int i; sprintf(buf, "pidof %s", proc_name); - if ((fp = popen(buf, "r")) == NULL ) { + + if ((fp = popen(buf, "r")) == NULL ) + { printf("xdemo: popen() failed\n"); return -1; } cptr = fgets(buf, 2047, fp); - if (cptr == NULL) { + + if (cptr == NULL) + { pclose(fp); return -1; } - num_procs = sscanf(buf, "%d %d %d %d %d %d %d %d %d %d", - &pids[0], &pids[1], &pids[2], &pids[3], &pids[4], + num_procs = sscanf(buf, "%d %d %d %d %d %d %d %d %d %d", + &pids[0], &pids[1], &pids[2], &pids[3], &pids[4], &pids[5], &pids[6], &pids[7], &pids[8], &pids[9]); - if (num_procs > 0) { - for (i = 0; i < num_procs; i++) { + + if (num_procs > 0) + { + for (i = 0; i < num_procs; i++) + { kill(pids[i], SIGUSR1); printf("sent SIGUSR1 to process %d\n", pids[i]); } diff --git a/xrdp/funcs.c b/xrdp/funcs.c index d30d5b90..82662fa9 100644 --- a/xrdp/funcs.c +++ b/xrdp/funcs.c @@ -1,240 +1,269 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - simple functions - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * simple functions + */ #include "xrdp.h" /*****************************************************************************/ /* returns boolean */ int APP_CC -rect_contains_pt(struct xrdp_rect* in, int x, int y) +rect_contains_pt(struct xrdp_rect *in, int x, int y) { - if (x < in->left) - { - return 0; - } - if (y < in->top) - { - return 0; - } - if (x >= in->right) - { - return 0; - } - if (y >= in->bottom) - { - return 0; - } - return 1; + if (x < in->left) + { + return 0; + } + + if (y < in->top) + { + return 0; + } + + if (x >= in->right) + { + return 0; + } + + if (y >= in->bottom) + { + return 0; + } + + return 1; } /*****************************************************************************/ int APP_CC -rect_intersect(struct xrdp_rect* in1, struct xrdp_rect* in2, - struct xrdp_rect* out) +rect_intersect(struct xrdp_rect *in1, struct xrdp_rect *in2, + struct xrdp_rect *out) { - int rv; - struct xrdp_rect dumby; + int rv; + struct xrdp_rect dumby; - if (out == 0) - { - out = &dumby; - } - *out = *in1; - if (in2->left > in1->left) - { - out->left = in2->left; - } - if (in2->top > in1->top) - { - out->top = in2->top; - } - if (in2->right < in1->right) - { - out->right = in2->right; - } - if (in2->bottom < in1->bottom) - { - out->bottom = in2->bottom; - } - rv = !ISRECTEMPTY(*out); - if (!rv) - { - g_memset(out, 0, sizeof(struct xrdp_rect)); - } - return rv; + if (out == 0) + { + out = &dumby; + } + + *out = *in1; + + if (in2->left > in1->left) + { + out->left = in2->left; + } + + if (in2->top > in1->top) + { + out->top = in2->top; + } + + if (in2->right < in1->right) + { + out->right = in2->right; + } + + if (in2->bottom < in1->bottom) + { + out->bottom = in2->bottom; + } + + rv = !ISRECTEMPTY(*out); + + if (!rv) + { + g_memset(out, 0, sizeof(struct xrdp_rect)); + } + + return rv; } /*****************************************************************************/ /* returns boolean */ int APP_CC -rect_contained_by(struct xrdp_rect* in1, int left, int top, +rect_contained_by(struct xrdp_rect *in1, int left, int top, int right, int bottom) { - if (left < in1->left || top < in1->top || - right > in1->right || bottom > in1->bottom) - { - return 0; - } - else - { - return 1; - } + if (left < in1->left || top < in1->top || + right > in1->right || bottom > in1->bottom) + { + return 0; + } + else + { + return 1; + } } /*****************************************************************************/ /* adjust the bounds to fit in the bitmap */ /* return false if there is nothing to draw else return true */ int APP_CC -check_bounds(struct xrdp_bitmap* b, int* x, int* y, int* cx, int* cy) +check_bounds(struct xrdp_bitmap *b, int *x, int *y, int *cx, int *cy) { - if (*x >= b->width) - { - return 0; - } - if (*y >= b->height) - { - return 0; - } - if (*x < 0) - { - *cx += *x; - *x = 0; - } - if (*y < 0) - { - *cy += *y; - *y = 0; - } - if (*cx <= 0) - { - return 0; - } - if (*cy <= 0) - { - return 0; - } - if (*x + *cx > b->width) - { - *cx = b->width - *x; - } - if (*y + *cy > b->height) - { - *cy = b->height - *y; - } - return 1; + if (*x >= b->width) + { + return 0; + } + + if (*y >= b->height) + { + return 0; + } + + if (*x < 0) + { + *cx += *x; + *x = 0; + } + + if (*y < 0) + { + *cy += *y; + *y = 0; + } + + if (*cx <= 0) + { + return 0; + } + + if (*cy <= 0) + { + return 0; + } + + if (*x + *cx > b->width) + { + *cx = b->width - *x; + } + + if (*y + *cy > b->height) + { + *cy = b->height - *y; + } + + return 1; } /*****************************************************************************/ /* add a ch at index position in text, index starts at 0 */ /* if index = -1 add it to the end */ int APP_CC -add_char_at(char* text, int text_size, twchar ch, int index) +add_char_at(char *text, int text_size, twchar ch, int index) { - int len; - int i; - twchar* wstr; + int len; + int i; + twchar *wstr; - len = g_mbstowcs(0, text, 0); - wstr = (twchar*)g_malloc((len + 16) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); - if ((index >= len) || (index < 0)) - { - wstr[len] = ch; + len = g_mbstowcs(0, text, 0); + wstr = (twchar *)g_malloc((len + 16) * sizeof(twchar), 0); + g_mbstowcs(wstr, text, len + 1); + + if ((index >= len) || (index < 0)) + { + wstr[len] = ch; + wstr[len + 1] = 0; + g_wcstombs(text, wstr, text_size); + g_free(wstr); + return 0; + } + + for (i = (len - 1); i >= index; i--) + { + wstr[i + 1] = wstr[i]; + } + + wstr[i + 1] = ch; wstr[len + 1] = 0; g_wcstombs(text, wstr, text_size); g_free(wstr); return 0; - } - for (i = (len - 1); i >= index; i--) - { - wstr[i + 1] = wstr[i]; - } - wstr[i + 1] = ch; - wstr[len + 1] = 0; - g_wcstombs(text, wstr, text_size); - g_free(wstr); - return 0; } /*****************************************************************************/ /* remove a ch at index position in text, index starts at 0 */ /* if index = -1 remove it from the end */ int APP_CC -remove_char_at(char* text, int text_size, int index) +remove_char_at(char *text, int text_size, int index) { - int len; - int i; - twchar* wstr; + int len; + int i; + twchar *wstr; + + len = g_mbstowcs(0, text, 0); + + if (len <= 0) + { + return 0; + } + + wstr = (twchar *)g_malloc((len + 16) * sizeof(twchar), 0); + g_mbstowcs(wstr, text, len + 1); + + if ((index >= (len - 1)) || (index < 0)) + { + wstr[len - 1] = 0; + g_wcstombs(text, wstr, text_size); + g_free(wstr); + return 0; + } + + for (i = index; i < (len - 1); i++) + { + wstr[i] = wstr[i + 1]; + } - len = g_mbstowcs(0, text, 0); - if (len <= 0) - { - return 0; - } - wstr = (twchar*)g_malloc((len + 16) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); - if ((index >= (len - 1)) || (index < 0)) - { wstr[len - 1] = 0; g_wcstombs(text, wstr, text_size); g_free(wstr); return 0; - } - for (i = index; i < (len - 1); i++) - { - wstr[i] = wstr[i + 1]; - } - wstr[len - 1] = 0; - g_wcstombs(text, wstr, text_size); - g_free(wstr); - return 0; } /*****************************************************************************/ int APP_CC -set_string(char** in_str, const char* in) +set_string(char **in_str, const char *in) { - if (in_str == 0) - { - return 0; - } - g_free(*in_str); - *in_str = g_strdup(in); - return 0; -} - -/*****************************************************************************/ -int APP_CC -wchar_repeat(twchar* dest, int dest_size_in_wchars, twchar ch, int repeat) -{ - int index; - - for (index = 0; index < repeat; index++) - { - if (index >= dest_size_in_wchars) + if (in_str == 0) { - break; + return 0; } - dest[index] = ch; - } - return 0; + + g_free(*in_str); + *in_str = g_strdup(in); + return 0; +} + +/*****************************************************************************/ +int APP_CC +wchar_repeat(twchar *dest, int dest_size_in_wchars, twchar ch, int repeat) +{ + int index; + + for (index = 0; index < repeat; index++) + { + if (index >= dest_size_in_wchars) + { + break; + } + + dest[index] = ch; + } + + return 0; } diff --git a/xrdp/lang.c b/xrdp/lang.c index 1c13839f..29031ea2 100644 --- a/xrdp/lang.c +++ b/xrdp/lang.c @@ -1,25 +1,23 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2006-2010 - - keylayout - maximum unicode 19996(0x4e00) - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * keylayout + * maximum unicode 19996(0x4e00) + */ #include "xrdp.h" #include "log.h" @@ -28,223 +26,241 @@ code1 is regular scancode, code2 is extended scancode */ struct codepair { - tui8 code1; - tui8 code2; + tui8 code1; + tui8 code2; }; static struct codepair g_map[] = { - { 0, 0 }, { 9, 0 }, { 10, 0 }, { 11, 0 }, { 12, 0 }, /* 0 - 4 */ - { 13, 0 }, { 14, 0 }, { 15, 0 }, { 16, 0 }, { 17, 0 }, /* 5 - 9 */ - { 18, 0 }, { 19, 0 }, { 20, 0 }, { 21, 0 }, { 22, 0 }, /* 10 - 14 */ - { 23, 0 }, { 24, 0 }, { 25, 0 }, { 26, 0 }, { 27, 0 }, /* 15 - 19 */ - { 28, 0 }, { 29, 0 }, { 30, 0 }, { 31, 0 }, { 32, 0 }, /* 20 - 24 */ - { 33, 0 }, { 34, 0 }, { 35, 0 }, { 36, 108 }, { 37, 109 }, /* 25 - 29 */ - { 38, 0 }, { 39, 0 }, { 40, 0 }, { 41, 0 }, { 42, 0 }, /* 30 - 34 */ - { 43, 0 }, { 44, 0 }, { 45, 0 }, { 46, 0 }, { 47, 0 }, /* 35 - 39 */ - { 48, 0 }, { 49, 0 }, { 50, 0 }, { 51, 0 }, { 52, 0 }, /* 40 - 44 */ - { 53, 0 }, { 54, 0 }, { 55, 0 }, { 56, 0 }, { 57, 0 }, /* 45 - 49 */ - { 58, 0 }, { 59, 0 }, { 60, 0 }, { 61, 112 }, { 62, 0 }, /* 50 - 54 */ - { 63, 111 }, { 64, 113 }, { 65, 0 }, { 66, 0 }, { 67, 0 }, /* 55 - 59 */ - { 68, 0 }, { 69, 0 }, { 70, 0 }, { 71, 0 }, { 72, 0 }, /* 60 - 64 */ - { 73, 0 }, { 74, 0 }, { 75, 0 }, { 76, 0 }, { 77, 0 }, /* 65 - 69 */ - { 78, 0 }, { 79, 97 }, { 80, 98 }, { 81, 99 }, { 82, 0 }, /* 70 - 74 */ - { 83, 100 }, { 84, 0 }, { 85, 102 }, { 86, 0 }, { 87, 103 }, /* 75 - 79 */ - { 88, 104 }, { 89, 105 }, { 90, 106 }, { 91, 107 }, { 92, 0 }, /* 80 - 84 */ - { 93, 0 }, { 94, 0 }, { 95, 0 }, { 96, 0 }, { 97, 0 }, /* 85 - 89 */ - { 98, 0 }, { 0, 115 }, { 0, 116 }, { 0, 117 }, { 102, 0 }, /* 90 - 94 */ - { 103, 0 }, { 104, 0 }, { 105, 0 }, { 106, 0 }, { 107, 0 }, /* 95 - 99 */ - { 108, 0 }, { 109, 0 }, { 110, 0 }, { 111, 0 }, { 112, 0 }, /* 100 - 104 */ - { 113, 0 }, { 114, 0 }, { 115, 0 }, { 116, 0 }, { 117, 0 }, /* 105 - 109 */ - { 118, 0 }, { 119, 0 }, { 120, 0 }, { 121, 0 }, { 122, 0 }, /* 110 - 114 */ - { 123, 0 }, { 124, 0 }, { 125, 0 }, { 126, 0 }, { 127, 0 }, /* 115 - 119 */ - { 128, 0 }, { 129, 0 }, { 130, 0 }, { 131, 0 }, { 132, 0 }, /* 120 - 124 */ - { 133, 0 }, { 134, 0 }, { 135, 0 } /* 125 - 127 */ + { 0, 0 }, { 9, 0 }, { 10, 0 }, { 11, 0 }, { 12, 0 }, /* 0 - 4 */ + { 13, 0 }, { 14, 0 }, { 15, 0 }, { 16, 0 }, { 17, 0 }, /* 5 - 9 */ + { 18, 0 }, { 19, 0 }, { 20, 0 }, { 21, 0 }, { 22, 0 }, /* 10 - 14 */ + { 23, 0 }, { 24, 0 }, { 25, 0 }, { 26, 0 }, { 27, 0 }, /* 15 - 19 */ + { 28, 0 }, { 29, 0 }, { 30, 0 }, { 31, 0 }, { 32, 0 }, /* 20 - 24 */ + { 33, 0 }, { 34, 0 }, { 35, 0 }, { 36, 108 }, { 37, 109 }, /* 25 - 29 */ + { 38, 0 }, { 39, 0 }, { 40, 0 }, { 41, 0 }, { 42, 0 }, /* 30 - 34 */ + { 43, 0 }, { 44, 0 }, { 45, 0 }, { 46, 0 }, { 47, 0 }, /* 35 - 39 */ + { 48, 0 }, { 49, 0 }, { 50, 0 }, { 51, 0 }, { 52, 0 }, /* 40 - 44 */ + { 53, 0 }, { 54, 0 }, { 55, 0 }, { 56, 0 }, { 57, 0 }, /* 45 - 49 */ + { 58, 0 }, { 59, 0 }, { 60, 0 }, { 61, 112 }, { 62, 0 }, /* 50 - 54 */ + { 63, 111 }, { 64, 113 }, { 65, 0 }, { 66, 0 }, { 67, 0 }, /* 55 - 59 */ + { 68, 0 }, { 69, 0 }, { 70, 0 }, { 71, 0 }, { 72, 0 }, /* 60 - 64 */ + { 73, 0 }, { 74, 0 }, { 75, 0 }, { 76, 0 }, { 77, 0 }, /* 65 - 69 */ + { 78, 0 }, { 79, 97 }, { 80, 98 }, { 81, 99 }, { 82, 0 }, /* 70 - 74 */ + { 83, 100 }, { 84, 0 }, { 85, 102 }, { 86, 0 }, { 87, 103 }, /* 75 - 79 */ + { 88, 104 }, { 89, 105 }, { 90, 106 }, { 91, 107 }, { 92, 0 }, /* 80 - 84 */ + { 93, 0 }, { 94, 0 }, { 95, 0 }, { 96, 0 }, { 97, 0 }, /* 85 - 89 */ + { 98, 0 }, { 0, 115 }, { 0, 116 }, { 0, 117 }, { 102, 0 }, /* 90 - 94 */ + { 103, 0 }, { 104, 0 }, { 105, 0 }, { 106, 0 }, { 107, 0 }, /* 95 - 99 */ + { 108, 0 }, { 109, 0 }, { 110, 0 }, { 111, 0 }, { 112, 0 }, /* 100 - 104 */ + { 113, 0 }, { 114, 0 }, { 115, 0 }, { 116, 0 }, { 117, 0 }, /* 105 - 109 */ + { 118, 0 }, { 119, 0 }, { 120, 0 }, { 121, 0 }, { 122, 0 }, /* 110 - 114 */ + { 123, 0 }, { 124, 0 }, { 125, 0 }, { 126, 0 }, { 127, 0 }, /* 115 - 119 */ + { 128, 0 }, { 129, 0 }, { 130, 0 }, { 131, 0 }, { 132, 0 }, /* 120 - 124 */ + { 133, 0 }, { 134, 0 }, { 135, 0 } /* 125 - 127 */ }; /*****************************************************************************/ -struct xrdp_key_info* APP_CC -get_key_info_from_scan_code(int device_flags, int scan_code, int* keys, +struct xrdp_key_info *APP_CC +get_key_info_from_scan_code(int device_flags, int scan_code, int *keys, int caps_lock, int num_lock, int scroll_lock, - struct xrdp_keymap* keymap) + struct xrdp_keymap *keymap) { - struct xrdp_key_info* rv; - int shift; - int altgr; - int ext; - int index; + struct xrdp_key_info *rv; + int shift; + int altgr; + int ext; + int index; - ext = device_flags & KBD_FLAG_EXT; /* 0x0100 */ - shift = keys[42] || keys[54]; - altgr = keys[56] & KBD_FLAG_EXT; /* right alt */ - rv = 0; - scan_code = scan_code & 0x7f; - index = ext ? g_map[scan_code].code2 : g_map[scan_code].code1; - /* keymap file is created with numlock off so we have to do this */ - if ((index >= 79) && (index <= 91)) - { - if (num_lock) + ext = device_flags &KBD_FLAG_EXT; /* 0x0100 */ + shift = keys[42] || keys[54]; + altgr = keys[56] &KBD_FLAG_EXT; /* right alt */ + rv = 0; + scan_code = scan_code & 0x7f; + index = ext ? g_map[scan_code].code2 : g_map[scan_code].code1; + + /* keymap file is created with numlock off so we have to do this */ + if ((index >= 79) && (index <= 91)) { - rv = &(keymap->keys_shift[index]); + if (num_lock) + { + rv = &(keymap->keys_shift[index]); + } + else + { + rv = &(keymap->keys_noshift[index]); + } + } + else if (shift && caps_lock) + { + rv = &(keymap->keys_shiftcapslock[index]); + } + else if (shift) + { + rv = &(keymap->keys_shift[index]); + } + else if (caps_lock) + { + rv = &(keymap->keys_capslock[index]); + } + else if (altgr) + { + rv = &(keymap->keys_altgr[index]); } else { - rv = &(keymap->keys_noshift[index]); + rv = &(keymap->keys_noshift[index]); } - } - else if (shift && caps_lock) - { - rv = &(keymap->keys_shiftcapslock[index]); - } - else if (shift) - { - rv = &(keymap->keys_shift[index]); - } - else if (caps_lock) - { - rv = &(keymap->keys_capslock[index]); - } - else if (altgr) - { - rv = &(keymap->keys_altgr[index]); - } - else - { - rv = &(keymap->keys_noshift[index]); - } - return rv; + + return rv; } /*****************************************************************************/ int APP_CC -get_keysym_from_scan_code(int device_flags, int scan_code, int* keys, +get_keysym_from_scan_code(int device_flags, int scan_code, int *keys, int caps_lock, int num_lock, int scroll_lock, - struct xrdp_keymap* keymap) + struct xrdp_keymap *keymap) { - struct xrdp_key_info* ki; + struct xrdp_key_info *ki; - ki = get_key_info_from_scan_code(device_flags, scan_code, keys, - caps_lock, num_lock, scroll_lock, - keymap); - if (ki == 0) - { - return 0; - } - return ki->sym; + ki = get_key_info_from_scan_code(device_flags, scan_code, keys, + caps_lock, num_lock, scroll_lock, + keymap); + + if (ki == 0) + { + return 0; + } + + return ki->sym; } /*****************************************************************************/ twchar APP_CC -get_char_from_scan_code(int device_flags, int scan_code, int* keys, +get_char_from_scan_code(int device_flags, int scan_code, int *keys, int caps_lock, int num_lock, int scroll_lock, - struct xrdp_keymap* keymap) + struct xrdp_keymap *keymap) { - struct xrdp_key_info* ki; + struct xrdp_key_info *ki; - ki = get_key_info_from_scan_code(device_flags, scan_code, keys, - caps_lock, num_lock, scroll_lock, - keymap); - if (ki == 0) - { - return 0; - } - return (twchar)(ki->chr); + ki = get_key_info_from_scan_code(device_flags, scan_code, keys, + caps_lock, num_lock, scroll_lock, + keymap); + + if (ki == 0) + { + return 0; + } + + return (twchar)(ki->chr); } /*****************************************************************************/ static int APP_CC -km_read_section(int fd, const char* section_name, struct xrdp_key_info* keymap) +km_read_section(int fd, const char *section_name, struct xrdp_key_info *keymap) { - struct list* names; - struct list* values; - int index; - int code; - int pos1; - char* name; - char* value; + struct list *names; + struct list *values; + int index; + int code; + int pos1; + char *name; + char *value; - names = list_create(); - names->auto_free = 1; - values = list_create(); - values->auto_free = 1; - if (file_read_section(fd, section_name, names, values) == 0) - { - for (index = names->count - 1; index >= 0; index--) + names = list_create(); + names->auto_free = 1; + values = list_create(); + values->auto_free = 1; + + if (file_read_section(fd, section_name, names, values) == 0) { - name = (char*)list_get_item(names, index); - value = (char*)list_get_item(values, index); - if ((name != 0) && (value != 0)) - { - if (g_strncasecmp(name, "key", 3) == 0) + for (index = names->count - 1; index >= 0; index--) { - code = g_atoi(name + 3); + name = (char *)list_get_item(names, index); + value = (char *)list_get_item(values, index); + + if ((name != 0) && (value != 0)) + { + if (g_strncasecmp(name, "key", 3) == 0) + { + code = g_atoi(name + 3); + } + else + { + code = g_atoi(name); + } + + if ((code >= 0) && (code < 256)) + { + pos1 = g_pos(value, ":"); + + if (pos1 >= 0) + { + keymap[code].chr = g_atoi(value + pos1 + 1); + } + + keymap[code].sym = g_atoi(value); + } + } } - else - { - code = g_atoi(name); - } - if ((code >= 0) && (code < 256)) - { - pos1 = g_pos(value, ":"); - if (pos1 >= 0) - { - keymap[code].chr = g_atoi(value + pos1 + 1); - } - keymap[code].sym = g_atoi(value); - } - } } - } - list_delete(names); - list_delete(values); - return 0; + + list_delete(names); + list_delete(values); + return 0; } /*****************************************************************************/ int APP_CC -get_keymaps(int keylayout, struct xrdp_keymap* keymap) +get_keymaps(int keylayout, struct xrdp_keymap *keymap) { - int fd; - char* filename; - struct xrdp_keymap* lkeymap; + int fd; + char *filename; + struct xrdp_keymap *lkeymap; - filename = (char*)g_malloc(256, 0); - /* check if there is a keymap file */ - g_snprintf(filename, 255, "%s/km-%4.4x.ini", XRDP_CFG_PATH, keylayout); - /* if the file does not exist, try again with 'en-us' as fallback */ - if (!g_file_exist(filename)) - { - g_snprintf(filename, 255, "%s/km-0409.ini", XRDP_CFG_PATH); - } - if (g_file_exist(filename)) - { - fd = g_file_open(filename); - if (fd > 0) + filename = (char *)g_malloc(256, 0); + /* check if there is a keymap file */ + g_snprintf(filename, 255, "%s/km-%4.4x.ini", XRDP_CFG_PATH, keylayout); + + /* if the file does not exist, try again with 'en-us' as fallback */ + if (!g_file_exist(filename)) { - lkeymap = (struct xrdp_keymap*)g_malloc(sizeof(struct xrdp_keymap), 0); - /* make a copy of the build in kaymap */ - g_memcpy(lkeymap, keymap, sizeof(struct xrdp_keymap)); - /* clear the keymaps */ - g_memset(keymap, 0, sizeof(struct xrdp_keymap)); - /* read the keymaps */ - km_read_section(fd, "noshift", keymap->keys_noshift); - km_read_section(fd, "shift", keymap->keys_shift); - km_read_section(fd, "altgr", keymap->keys_altgr); - km_read_section(fd, "capslock", keymap->keys_capslock); - km_read_section(fd, "shiftcapslock", keymap->keys_shiftcapslock); - if (g_memcmp(lkeymap, keymap, sizeof(struct xrdp_keymap)) != 0) - { - log_message(LOG_LEVEL_WARNING, - "local keymap file for 0x%4.4x found and dosen't match " - "built in keymap, using local keymap file", keylayout); - } - g_free(lkeymap); - g_file_close(fd); + g_snprintf(filename, 255, "%s/km-0409.ini", XRDP_CFG_PATH); } - } - else - { - log_message(LOG_LEVEL_WARNING,"File does not exist: %s",filename); - } - g_free(filename); - return 0; + + if (g_file_exist(filename)) + { + fd = g_file_open(filename); + + if (fd > 0) + { + lkeymap = (struct xrdp_keymap *)g_malloc(sizeof(struct xrdp_keymap), 0); + /* make a copy of the build in kaymap */ + g_memcpy(lkeymap, keymap, sizeof(struct xrdp_keymap)); + /* clear the keymaps */ + g_memset(keymap, 0, sizeof(struct xrdp_keymap)); + /* read the keymaps */ + km_read_section(fd, "noshift", keymap->keys_noshift); + km_read_section(fd, "shift", keymap->keys_shift); + km_read_section(fd, "altgr", keymap->keys_altgr); + km_read_section(fd, "capslock", keymap->keys_capslock); + km_read_section(fd, "shiftcapslock", keymap->keys_shiftcapslock); + + if (g_memcmp(lkeymap, keymap, sizeof(struct xrdp_keymap)) != 0) + { + log_message(LOG_LEVEL_WARNING, + "local keymap file for 0x%4.4x found and dosen't match " + "built in keymap, using local keymap file", keylayout); + } + + g_free(lkeymap); + g_file_close(fd); + } + } + else + { + log_message(LOG_LEVEL_WARNING, "File does not exist: %s", filename); + } + + g_free(filename); + return 0; } diff --git a/xrdp/xrdp.c b/xrdp/xrdp.c index 4af8c4d7..0da7a101 100644 --- a/xrdp/xrdp.c +++ b/xrdp/xrdp.c @@ -1,31 +1,29 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2012 - - main program - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * main program + */ #include "xrdp.h" #include "log.h" #define THREAD_WAITING 100 -static struct xrdp_listen* g_listen = 0; +static struct xrdp_listen *g_listen = 0; static long g_threadid = 0; /* main threadid */ static long g_sync_mutex = 0; @@ -47,73 +45,77 @@ long APP_CC g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1, long sync_param2) { - long sync_result; - int sync_command; + long sync_result; + int sync_command; - /* If the function is called from the main thread, the function can - * be called directly. g_threadid= main thread ID*/ - if (tc_threadid_equal(tc_get_threadid(), g_threadid)) - { - /* this is the main thread, call the function directly */ - /* in fork mode, this always happens too */ - sync_result = sync_func(sync_param1, sync_param2); - /*g_writeln("g_xrdp_sync processed IN main thread -> continue");*/ - } - else - { - /* All threads have to wait here until the main thread - * process the function. g_process_waiting_function() is called - * from the listening thread. g_process_waiting_function() process the function*/ - tc_mutex_lock(g_sync1_mutex); - tc_mutex_lock(g_sync_mutex); - g_sync_param1 = sync_param1; - g_sync_param2 = sync_param2; - g_sync_func = sync_func; - /* set a value THREAD_WAITING so the g_process_waiting_function function - * know if any function must be processed */ - g_sync_command = THREAD_WAITING; - tc_mutex_unlock(g_sync_mutex); - /* set this event so that the main thread know if - * g_process_waiting_function() must be called */ - g_set_wait_obj(g_sync_event); - do + /* If the function is called from the main thread, the function can + * be called directly. g_threadid= main thread ID*/ + if (tc_threadid_equal(tc_get_threadid(), g_threadid)) { - g_sleep(100); - tc_mutex_lock(g_sync_mutex); - /* load new value from global to see if the g_process_waiting_function() - * function has processed the function */ - sync_command = g_sync_command; - sync_result = g_sync_result; - tc_mutex_unlock(g_sync_mutex); + /* this is the main thread, call the function directly */ + /* in fork mode, this always happens too */ + sync_result = sync_func(sync_param1, sync_param2); + /*g_writeln("g_xrdp_sync processed IN main thread -> continue");*/ } - while (sync_command != 0); /* loop until g_process_waiting_function() + else + { + /* All threads have to wait here until the main thread + * process the function. g_process_waiting_function() is called + * from the listening thread. g_process_waiting_function() process the function*/ + tc_mutex_lock(g_sync1_mutex); + tc_mutex_lock(g_sync_mutex); + g_sync_param1 = sync_param1; + g_sync_param2 = sync_param2; + g_sync_func = sync_func; + /* set a value THREAD_WAITING so the g_process_waiting_function function + * know if any function must be processed */ + g_sync_command = THREAD_WAITING; + tc_mutex_unlock(g_sync_mutex); + /* set this event so that the main thread know if + * g_process_waiting_function() must be called */ + g_set_wait_obj(g_sync_event); + + do + { + g_sleep(100); + tc_mutex_lock(g_sync_mutex); + /* load new value from global to see if the g_process_waiting_function() + * function has processed the function */ + sync_command = g_sync_command; + sync_result = g_sync_result; + tc_mutex_unlock(g_sync_mutex); + } + while (sync_command != 0); /* loop until g_process_waiting_function() + * has processed the request */ - tc_mutex_unlock(g_sync1_mutex); - /*g_writeln("g_xrdp_sync processed BY main thread -> continue");*/ - } - return sync_result; + tc_mutex_unlock(g_sync1_mutex); + /*g_writeln("g_xrdp_sync processed BY main thread -> continue");*/ + } + + return sync_result; } /*****************************************************************************/ void DEFAULT_CC xrdp_shutdown(int sig) { - tbus threadid; + tbus threadid; - threadid = tc_get_threadid(); - g_writeln("shutting down"); - g_writeln("signal %d threadid %p", sig, threadid); - if (!g_is_wait_obj_set(g_term_event)) - { - g_set_wait_obj(g_term_event); - } + threadid = tc_get_threadid(); + g_writeln("shutting down"); + g_writeln("signal %d threadid %p", sig, threadid); + + if (!g_is_wait_obj_set(g_term_event)) + { + g_set_wait_obj(g_term_event); + } } /*****************************************************************************/ void DEFAULT_CC xrdp_child(int sig) { - g_waitchild(); + g_waitchild(); } /*****************************************************************************/ @@ -121,61 +123,61 @@ xrdp_child(int sig) int APP_CC xrdp_child_fork(void) { - int pid; - char text[256]; + int pid; + char text[256]; - /* close, don't delete these */ - g_close_wait_obj(g_term_event); - g_close_wait_obj(g_sync_event); - pid = g_getpid(); - g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); - g_term_event = g_create_wait_obj(text); - g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); - g_sync_event = g_create_wait_obj(text); - return 0; + /* close, don't delete these */ + g_close_wait_obj(g_term_event); + g_close_wait_obj(g_sync_event); + pid = g_getpid(); + g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); + g_term_event = g_create_wait_obj(text); + g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); + g_sync_event = g_create_wait_obj(text); + return 0; } /*****************************************************************************/ int APP_CC g_is_term(void) { - return g_is_wait_obj_set(g_term_event); + return g_is_wait_obj_set(g_term_event); } /*****************************************************************************/ void APP_CC g_set_term(int in_val) { - if (in_val) - { - g_set_wait_obj(g_term_event); - } - else - { - g_reset_wait_obj(g_term_event); - } + if (in_val) + { + g_set_wait_obj(g_term_event); + } + else + { + g_reset_wait_obj(g_term_event); + } } /*****************************************************************************/ tbus APP_CC g_get_term_event(void) { - return g_term_event; + return g_term_event; } /*****************************************************************************/ tbus APP_CC g_get_sync_event(void) { - return g_sync_event; + return g_sync_event; } /*****************************************************************************/ void DEFAULT_CC pipe_sig(int sig_num) { - /* do nothing */ - g_writeln("got SIGPIPE(%d)", sig_num); + /* do nothing */ + g_writeln("got SIGPIPE(%d)", sig_num); } /*****************************************************************************/ @@ -184,357 +186,400 @@ pipe_sig(int sig_num) void APP_CC g_process_waiting_function(void) { - tc_mutex_lock(g_sync_mutex); - if (g_sync_command != 0) - { - if (g_sync_func != 0) + tc_mutex_lock(g_sync_mutex); + + if (g_sync_command != 0) { - if (g_sync_command == THREAD_WAITING) - { - g_sync_result = g_sync_func(g_sync_param1, g_sync_param2); - } + if (g_sync_func != 0) + { + if (g_sync_command == THREAD_WAITING) + { + g_sync_result = g_sync_func(g_sync_param1, g_sync_param2); + } + } + + g_sync_command = 0; } - g_sync_command = 0; - } - tc_mutex_unlock(g_sync_mutex); + + tc_mutex_unlock(g_sync_mutex); } /*****************************************************************************/ int APP_CC -xrdp_process_params(int argc, char** argv, - struct xrdp_startup_params* startup_params) +xrdp_process_params(int argc, char **argv, + struct xrdp_startup_params *startup_params) { - int index; - char option[128]; - char value[128]; + int index; + char option[128]; + char value[128]; - index = 1; - while (index < argc) - { - g_strncpy(option, argv[index], 127); - if (index + 1 < argc) + index = 1; + + while (index < argc) { - g_strncpy(value, argv[index + 1], 127); + g_strncpy(option, argv[index], 127); + + if (index + 1 < argc) + { + g_strncpy(value, argv[index + 1], 127); + } + else + { + value[0] = 0; + } + + if ((g_strncasecmp(option, "-help", 255)) == 0 || + (g_strncasecmp(option, "--help", 255)) == 0 || + (g_strncasecmp(option, "-h", 255)) == 0) + { + startup_params->help = 1; + } + else if ((g_strncasecmp(option, "-kill", 255) == 0) || + (g_strncasecmp(option, "--kill", 255) == 0) || + (g_strncasecmp(option, "-k", 255) == 0)) + { + startup_params->kill = 1; + } + else if ((g_strncasecmp(option, "-nodaemon", 255) == 0) || + (g_strncasecmp(option, "--nodaemon", 255) == 0) || + (g_strncasecmp(option, "-nd", 255) == 0) || + (g_strncasecmp(option, "--nd", 255) == 0) || + (g_strncasecmp(option, "-ns", 255) == 0) || + (g_strncasecmp(option, "--ns", 255) == 0)) + { + startup_params->no_daemon = 1; + } + else if ((g_strncasecmp(option, "-v", 255) == 0) || + (g_strncasecmp(option, "--version", 255) == 0)) + { + startup_params->version = 1; + } + else if ((g_strncasecmp(option, "-p", 255) == 0) || + (g_strncasecmp(option, "--port", 255) == 0)) + { + index++; + g_strncpy(startup_params->port, value, 127); + + if (g_strlen(startup_params->port) < 1) + { + g_writeln("error processing params, port [%s]", startup_params->port); + return 1; + } + else + { + g_writeln("--port parameter found, ini override [%s]", + startup_params->port); + } + } + else if ((g_strncasecmp(option, "-f", 255) == 0) || + (g_strncasecmp(option, "--fork", 255) == 0)) + { + startup_params->fork = 1; + g_writeln("--fork parameter found, ini override"); + } + else + { + return 1; + } + + index++; } - else - { - value[0] = 0; - } - if ((g_strncasecmp(option, "-help", 255)) == 0 || - (g_strncasecmp(option, "--help", 255)) == 0 || - (g_strncasecmp(option, "-h", 255)) == 0) - { - startup_params->help = 1; - } - else if ((g_strncasecmp(option, "-kill", 255) == 0) || - (g_strncasecmp(option, "--kill", 255) == 0) || - (g_strncasecmp(option, "-k", 255) == 0)) - { - startup_params->kill = 1; - } - else if ((g_strncasecmp(option, "-nodaemon", 255) == 0) || - (g_strncasecmp(option, "--nodaemon", 255) == 0) || - (g_strncasecmp(option, "-nd", 255) == 0) || - (g_strncasecmp(option, "--nd", 255) == 0) || - (g_strncasecmp(option, "-ns", 255) == 0) || - (g_strncasecmp(option, "--ns", 255) == 0)) - { - startup_params->no_daemon = 1; - } - else if ((g_strncasecmp(option, "-v", 255) == 0) || - (g_strncasecmp(option, "--version", 255) == 0)) - { - startup_params->version = 1; - } - else if ((g_strncasecmp(option, "-p", 255) == 0) || - (g_strncasecmp(option, "--port", 255) == 0)) - { - index++; - g_strncpy(startup_params->port, value, 127); - if (g_strlen(startup_params->port) < 1) - { - g_writeln("error processing params, port [%s]", startup_params->port); - return 1; - } - else - { - g_writeln("--port parameter found, ini override [%s]", - startup_params->port); - } - } - else if ((g_strncasecmp(option, "-f", 255) == 0) || - (g_strncasecmp(option, "--fork", 255) == 0)) - { - startup_params->fork = 1; - g_writeln("--fork parameter found, ini override"); - } - else - { - return 1; - } - index++; - } - return 0; + + return 0; } /*****************************************************************************/ int DEFAULT_CC -main(int argc, char** argv) +main(int argc, char **argv) { - int test; - int host_be; - char cfg_file[256]; - enum logReturns error; - struct xrdp_startup_params* startup_params; - int pid; - int fd; - int no_daemon; - char text[256]; - char pid_file[256]; + int test; + int host_be; + char cfg_file[256]; + enum logReturns error; + struct xrdp_startup_params *startup_params; + int pid; + int fd; + int no_daemon; + char text[256]; + char pid_file[256]; - g_init("xrdp"); - ssl_init(); - /* check compiled endian with actual endian */ - test = 1; - host_be = !((int)(*(unsigned char*)(&test))); + g_init("xrdp"); + ssl_init(); + /* check compiled endian with actual endian */ + test = 1; + host_be = !((int)(*(unsigned char *)(&test))); #if defined(B_ENDIAN) - if (!host_be) + + if (!host_be) #endif #if defined(L_ENDIAN) - if (host_be) + if (host_be) #endif - { - g_writeln("endian wrong, edit arch.h"); - return 0; - } - /* check long, int and void* sizes */ - if (sizeof(int) != 4) - { - g_writeln("unusable int size, must be 4"); - return 0; - } - if (sizeof(long) != sizeof(void*)) - { - g_writeln("long size must match void* size"); - return 0; - } - if (sizeof(long) != 4 && sizeof(long) != 8) - { - g_writeln("unusable long size, must be 4 or 8"); - return 0; - } - if (sizeof(tui64) != 8) - { - g_writeln("unusable tui64 size, must be 8"); - return 0; - } - g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + { + g_writeln("endian wrong, edit arch.h"); + return 0; + } - /* starting logging subsystem */ - error = log_start(cfg_file, "XRDP"); - - if (error != LOG_STARTUP_OK) - { - switch (error) + /* check long, int and void* sizes */ + if (sizeof(int) != 4) { - case LOG_ERROR_MALLOC: - g_writeln("error on malloc. cannot start logging. quitting."); - break; - case LOG_ERROR_FILE_OPEN: - g_writeln("error opening log file [%s]. quitting.", - getLogFile(text, 255)); - break; - default: - g_writeln("log_start error"); - break; + g_writeln("unusable int size, must be 4"); + return 0; } - g_deinit(); - g_exit(1); - } - startup_params = (struct xrdp_startup_params*) - g_malloc(sizeof(struct xrdp_startup_params), 1); - if (xrdp_process_params(argc, argv, startup_params) != 0) - { - g_writeln("Unknown Parameter"); - g_writeln("xrdp -h for help"); - g_writeln(""); - g_deinit(); - g_exit(0); - } + if (sizeof(long) != sizeof(void *)) + { + g_writeln("long size must match void* size"); + return 0; + } - g_snprintf(pid_file, 255, "%s/xrdp.pid", XRDP_PID_PATH); - no_daemon = 0; + if (sizeof(long) != 4 && sizeof(long) != 8) + { + g_writeln("unusable long size, must be 4 or 8"); + return 0; + } + + if (sizeof(tui64) != 8) + { + g_writeln("unusable tui64 size, must be 8"); + return 0; + } + + g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + + /* starting logging subsystem */ + error = log_start(cfg_file, "XRDP"); + + if (error != LOG_STARTUP_OK) + { + switch (error) + { + case LOG_ERROR_MALLOC: + g_writeln("error on malloc. cannot start logging. quitting."); + break; + case LOG_ERROR_FILE_OPEN: + g_writeln("error opening log file [%s]. quitting.", + getLogFile(text, 255)); + break; + default: + g_writeln("log_start error"); + break; + } + + g_deinit(); + g_exit(1); + } + + startup_params = (struct xrdp_startup_params *) + g_malloc(sizeof(struct xrdp_startup_params), 1); + + if (xrdp_process_params(argc, argv, startup_params) != 0) + { + g_writeln("Unknown Parameter"); + g_writeln("xrdp -h for help"); + g_writeln(""); + g_deinit(); + g_exit(0); + } + + g_snprintf(pid_file, 255, "%s/xrdp.pid", XRDP_PID_PATH); + no_daemon = 0; + + if (startup_params->kill) + { + g_writeln("stopping xrdp"); + /* read the xrdp.pid file */ + fd = -1; + + if (g_file_exist(pid_file)) /* xrdp.pid */ + { + fd = g_file_open(pid_file); /* xrdp.pid */ + } + + if (fd == -1) + { + g_writeln("problem opening to xrdp.pid [%s]", pid_file); + g_writeln("maybe its not running"); + } + else + { + g_memset(text, 0, 32); + g_file_read(fd, text, 31); + pid = g_atoi(text); + g_writeln("stopping process id %d", pid); + + if (pid > 0) + { + g_sigterm(pid); + } + + g_file_close(fd); + } + + g_deinit(); + g_exit(0); + } + + if (startup_params->no_daemon) + { + no_daemon = 1; + } + + if (startup_params->help) + { + g_writeln(""); + g_writeln("xrdp: A Remote Desktop Protocol server."); + g_writeln("Copyright (C) Jay Sorg 2004-2011"); + g_writeln("See http://xrdp.sourceforge.net for more information."); + g_writeln(""); + g_writeln("Usage: xrdp [options]"); + g_writeln(" --help: show help"); + g_writeln(" --nodaemon: don't fork into background"); + g_writeln(" --kill: shut down xrdp"); + g_writeln(" --port: tcp listen port"); + g_writeln(" --fork: fork on new connection"); + g_writeln(""); + g_deinit(); + g_exit(0); + } + + if (startup_params->version) + { + g_writeln(""); + g_writeln("xrdp: A Remote Desktop Protocol server."); + g_writeln("Copyright (C) Jay Sorg 2004-2011"); + g_writeln("See http://xrdp.sourceforge.net for more information."); + g_writeln("Version %s", PACKAGE_VERSION); + g_writeln(""); + g_deinit(); + g_exit(0); + } - if (startup_params->kill) - { - g_writeln("stopping xrdp"); - /* read the xrdp.pid file */ - fd = -1; if (g_file_exist(pid_file)) /* xrdp.pid */ { - fd = g_file_open(pid_file); /* xrdp.pid */ + g_writeln("It looks like xrdp is allready running,"); + g_writeln("if not delete the xrdp.pid file and try again"); + g_deinit(); + g_exit(0); } - if (fd == -1) - { - g_writeln("problem opening to xrdp.pid [%s]", pid_file); - g_writeln("maybe its not running"); - } - else - { - g_memset(text, 0, 32); - g_file_read(fd, text, 31); - pid = g_atoi(text); - g_writeln("stopping process id %d", pid); - if (pid > 0) - { - g_sigterm(pid); - } - g_file_close(fd); - } - g_deinit(); - g_exit(0); - } - if (startup_params->no_daemon) - { - no_daemon = 1; - } - if (startup_params->help) - { - g_writeln(""); - g_writeln("xrdp: A Remote Desktop Protocol server."); - g_writeln("Copyright (C) Jay Sorg 2004-2011"); - g_writeln("See http://xrdp.sourceforge.net for more information."); - g_writeln(""); - g_writeln("Usage: xrdp [options]"); - g_writeln(" --help: show help"); - g_writeln(" --nodaemon: don't fork into background"); - g_writeln(" --kill: shut down xrdp"); - g_writeln(" --port: tcp listen port"); - g_writeln(" --fork: fork on new connection"); - g_writeln(""); - g_deinit(); - g_exit(0); - } - if (startup_params->version) - { - g_writeln(""); - g_writeln("xrdp: A Remote Desktop Protocol server."); - g_writeln("Copyright (C) Jay Sorg 2004-2011"); - g_writeln("See http://xrdp.sourceforge.net for more information."); - g_writeln("Version %s",PACKAGE_VERSION); - g_writeln(""); - g_deinit(); - g_exit(0); - } - if (g_file_exist(pid_file)) /* xrdp.pid */ - { - g_writeln("It looks like xrdp is allready running,"); - g_writeln("if not delete the xrdp.pid file and try again"); - g_deinit(); - g_exit(0); - } - if (!no_daemon) - { - /* make sure containing directory exists */ - g_create_path(pid_file); + if (!no_daemon) + { - /* make sure we can write to pid file */ - fd = g_file_open(pid_file); /* xrdp.pid */ - if (fd == -1) - { - g_writeln("running in daemon mode with no access to pid files, quitting"); - g_deinit(); - g_exit(0); + /* make sure containing directory exists */ + g_create_path(pid_file); + + /* make sure we can write to pid file */ + fd = g_file_open(pid_file); /* xrdp.pid */ + + if (fd == -1) + { + g_writeln("running in daemon mode with no access to pid files, quitting"); + g_deinit(); + g_exit(0); + } + + if (g_file_write(fd, "0", 1) == -1) + { + g_writeln("running in daemon mode with no access to pid files, quitting"); + g_deinit(); + g_exit(0); + } + + g_file_close(fd); + g_file_delete(pid_file); } - if (g_file_write(fd, "0", 1) == -1) + + if (!no_daemon) { - g_writeln("running in daemon mode with no access to pid files, quitting"); - g_deinit(); - g_exit(0); + /* start of daemonizing code */ + pid = g_fork(); + + if (pid == -1) + { + g_writeln("problem forking"); + g_deinit(); + g_exit(1); + } + + if (0 != pid) + { + g_writeln("process %d started ok", pid); + /* exit, this is the main process */ + g_deinit(); + g_exit(0); + } + + g_sleep(1000); + /* write the pid to file */ + pid = g_getpid(); + fd = g_file_open(pid_file); /* xrdp.pid */ + + if (fd == -1) + { + g_writeln("trying to write process id to xrdp.pid"); + g_writeln("problem opening xrdp.pid"); + g_writeln("maybe no rights"); + } + else + { + g_sprintf(text, "%d", pid); + g_file_write(fd, text, g_strlen(text)); + g_file_close(fd); + } + + g_sleep(1000); + g_file_close(0); + g_file_close(1); + g_file_close(2); + g_file_open("/dev/null"); + g_file_open("/dev/null"); + g_file_open("/dev/null"); + /* end of daemonizing code */ } - g_file_close(fd); - g_file_delete(pid_file); - } - if (!no_daemon) - { - /* start of daemonizing code */ - pid = g_fork(); - if (pid == -1) - { - g_writeln("problem forking"); - g_deinit(); - g_exit(1); - } - if (0 != pid) - { - g_writeln("process %d started ok", pid); - /* exit, this is the main process */ - g_deinit(); - g_exit(0); - } - g_sleep(1000); - /* write the pid to file */ + + g_threadid = tc_get_threadid(); + g_listen = xrdp_listen_create(); + g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */ + g_signal_kill(xrdp_shutdown); /* SIGKILL */ + g_signal_pipe(pipe_sig); /* SIGPIPE */ + g_signal_terminate(xrdp_shutdown); /* SIGTERM */ + g_signal_child_stop(xrdp_child); /* SIGCHLD */ + g_sync_mutex = tc_mutex_create(); + g_sync1_mutex = tc_mutex_create(); pid = g_getpid(); - fd = g_file_open(pid_file); /* xrdp.pid */ - if (fd == -1) + g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); + g_term_event = g_create_wait_obj(text); + + if (g_term_event == 0) { - g_writeln("trying to write process id to xrdp.pid"); - g_writeln("problem opening xrdp.pid"); - g_writeln("maybe no rights"); + g_writeln("error creating g_term_event"); } - else + + g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); + g_sync_event = g_create_wait_obj(text); + + if (g_sync_event == 0) { - g_sprintf(text, "%d", pid); - g_file_write(fd, text, g_strlen(text)); - g_file_close(fd); + g_writeln("error creating g_sync_event"); } - g_sleep(1000); - g_file_close(0); - g_file_close(1); - g_file_close(2); - g_file_open("/dev/null"); - g_file_open("/dev/null"); - g_file_open("/dev/null"); - /* end of daemonizing code */ - } - g_threadid = tc_get_threadid(); - g_listen = xrdp_listen_create(); - g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */ - g_signal_kill(xrdp_shutdown); /* SIGKILL */ - g_signal_pipe(pipe_sig); /* SIGPIPE */ - g_signal_terminate(xrdp_shutdown); /* SIGTERM */ - g_signal_child_stop(xrdp_child); /* SIGCHLD */ - g_sync_mutex = tc_mutex_create(); - g_sync1_mutex = tc_mutex_create(); - pid = g_getpid(); - g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); - g_term_event = g_create_wait_obj(text); - if (g_term_event == 0) - { - g_writeln("error creating g_term_event"); - } - g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); - g_sync_event = g_create_wait_obj(text); - if (g_sync_event == 0) - { - g_writeln("error creating g_sync_event"); - } - g_listen->startup_params = startup_params; - xrdp_listen_main_loop(g_listen); - xrdp_listen_delete(g_listen); - tc_mutex_delete(g_sync_mutex); - tc_mutex_delete(g_sync1_mutex); - g_delete_wait_obj(g_term_event); - g_delete_wait_obj(g_sync_event); - /* only main process should delete pid file */ - if ((!no_daemon) && (pid == g_getpid())) - { - /* delete the xrdp.pid file */ - g_file_delete(pid_file); - } - g_free(startup_params); - g_deinit(); - return 0; + + g_listen->startup_params = startup_params; + xrdp_listen_main_loop(g_listen); + xrdp_listen_delete(g_listen); + tc_mutex_delete(g_sync_mutex); + tc_mutex_delete(g_sync1_mutex); + g_delete_wait_obj(g_term_event); + g_delete_wait_obj(g_sync_event); + + /* only main process should delete pid file */ + if ((!no_daemon) && (pid == g_getpid())) + { + /* delete the xrdp.pid file */ + g_file_delete(pid_file); + } + + g_free(startup_params); + g_deinit(); + return 0; } diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 2f4e7eb6..a98acb16 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - main include file - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * main include file + */ /* include other h files */ #if defined(HAVE_CONFIG_H) diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c index 828c5139..d60cc920 100644 --- a/xrdp/xrdp_bitmap.c +++ b/xrdp/xrdp_bitmap.c @@ -1,27 +1,25 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - bitmap, drawable - this is a object that can be drawn on with a painter - all windows, bitmaps, even the screen are of this type - maybe it should be called xrdp_drawable - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * bitmap, drawable + * this is a object that can be drawn on with a painter + * all windows, bitmaps, even the screen are of this type + * maybe it should be called xrdp_drawable + */ #include "xrdp.h" #include "log.h" @@ -29,303 +27,348 @@ static int g_crc_seed = 0xffffffff; static int g_crc_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; #define CRC_START(in_crc) (in_crc) = g_crc_seed #define CRC_PASS(in_pixel, in_crc) \ - (in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8) + (in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8) #define CRC_END(in_crc) (in_crc) = ((in_crc) ^ g_crc_seed) /*****************************************************************************/ -struct xrdp_bitmap* APP_CC +struct xrdp_bitmap *APP_CC xrdp_bitmap_create(int width, int height, int bpp, - int type, struct xrdp_wm* wm) + int type, struct xrdp_wm *wm) { - struct xrdp_bitmap* self = (struct xrdp_bitmap *)NULL; - int Bpp = 0; + struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL; + int Bpp = 0; - self = (struct xrdp_bitmap*)g_malloc(sizeof(struct xrdp_bitmap), 1); - self->type = type; - self->width = width; - self->height = height; - self->bpp = bpp; - Bpp = 4; - switch (bpp) - { - case 8: Bpp = 1; break; - case 15: Bpp = 2; break; - case 16: Bpp = 2; break; - } - if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE) - { - self->data = (char*)g_malloc(width * height * Bpp, 0); - } - if (self->type != WND_TYPE_BITMAP) - { - self->child_list = list_create(); - } - self->line_size = width * Bpp; - if (self->type == WND_TYPE_COMBO) - { - self->string_list = list_create(); - self->string_list->auto_free = 1; - self->data_list = list_create(); - self->data_list->auto_free = 1; - } - self->wm = wm; - return self; + self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1); + self->type = type; + self->width = width; + self->height = height; + self->bpp = bpp; + Bpp = 4; + + switch (bpp) + { + case 8: + Bpp = 1; + break; + case 15: + Bpp = 2; + break; + case 16: + Bpp = 2; + break; + } + + if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE) + { + self->data = (char *)g_malloc(width * height * Bpp, 0); + } + + if (self->type != WND_TYPE_BITMAP) + { + self->child_list = list_create(); + } + + self->line_size = width *Bpp; + + if (self->type == WND_TYPE_COMBO) + { + self->string_list = list_create(); + self->string_list->auto_free = 1; + self->data_list = list_create(); + self->data_list->auto_free = 1; + } + + self->wm = wm; + return self; } /*****************************************************************************/ -struct xrdp_bitmap* APP_CC +struct xrdp_bitmap *APP_CC xrdp_bitmap_create_with_data(int width, int height, - int bpp, char* data, - struct xrdp_wm* wm) + int bpp, char *data, + struct xrdp_wm *wm) { - struct xrdp_bitmap* self = (struct xrdp_bitmap *)NULL; + struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL; - self = (struct xrdp_bitmap*)g_malloc(sizeof(struct xrdp_bitmap), 1); - self->type = WND_TYPE_BITMAP; - self->width = width; - self->height = height; - self->bpp = bpp; - self->data = data; - self->do_not_free_data = 1; - self->wm = wm; - return self; + self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1); + self->type = WND_TYPE_BITMAP; + self->width = width; + self->height = height; + self->bpp = bpp; + self->data = data; + self->do_not_free_data = 1; + self->wm = wm; + return self; } /*****************************************************************************/ void APP_CC -xrdp_bitmap_delete(struct xrdp_bitmap* self) +xrdp_bitmap_delete(struct xrdp_bitmap *self) { - int i = 0; - struct xrdp_mod_data* mod_data = (struct xrdp_mod_data *)NULL; + int i = 0; + struct xrdp_mod_data *mod_data = (struct xrdp_mod_data *)NULL; - if (self == 0) - { - return; - } - if (self->wm != 0) - { - if (self->wm->focused_window != 0) + if (self == 0) { - if (self->wm->focused_window->focused_control == self) - { - self->wm->focused_window->focused_control = 0; - } + return; } - if (self->wm->focused_window == self) + + if (self->wm != 0) { - self->wm->focused_window = 0; + if (self->wm->focused_window != 0) + { + if (self->wm->focused_window->focused_control == self) + { + self->wm->focused_window->focused_control = 0; + } + } + + if (self->wm->focused_window == self) + { + self->wm->focused_window = 0; + } + + if (self->wm->dragging_window == self) + { + self->wm->dragging_window = 0; + } + + if (self->wm->button_down == self) + { + self->wm->button_down = 0; + } + + if (self->wm->popup_wnd == self) + { + self->wm->popup_wnd = 0; + } + + if (self->wm->login_window == self) + { + self->wm->login_window = 0; + } + + if (self->wm->log_wnd == self) + { + self->wm->log_wnd = 0; + } } - if (self->wm->dragging_window == self) + + if (self->child_list != 0) { - self->wm->dragging_window = 0; + for (i = self->child_list->count - 1; i >= 0; i--) + { + xrdp_bitmap_delete((struct xrdp_bitmap *)self->child_list->items[i]); + } + + list_delete(self->child_list); } - if (self->wm->button_down == self) + + if (self->parent != 0) { - self->wm->button_down = 0; + i = list_index_of(self->parent->child_list, (long)self); + + if (i >= 0) + { + list_remove_item(self->parent->child_list, i); + } } - if (self->wm->popup_wnd == self) + + if (self->string_list != 0) /* for combo */ { - self->wm->popup_wnd = 0; + list_delete(self->string_list); } - if (self->wm->login_window == self) + + if (self->data_list != 0) /* for combo */ { - self->wm->login_window = 0; + for (i = 0; i < self->data_list->count; i++) + { + mod_data = (struct xrdp_mod_data *)list_get_item(self->data_list, i); + + if (mod_data != 0) + { + list_delete(mod_data->names); + list_delete(mod_data->values); + } + } + + list_delete(self->data_list); } - if (self->wm->log_wnd == self) + + if (!self->do_not_free_data) { - self->wm->log_wnd = 0; + g_free(self->data); } - } - if (self->child_list != 0) - { - for (i = self->child_list->count - 1; i >= 0; i--) - { - xrdp_bitmap_delete((struct xrdp_bitmap*)self->child_list->items[i]); - } - list_delete(self->child_list); - } - if (self->parent != 0) - { - i = list_index_of(self->parent->child_list, (long)self); - if (i >= 0) - { - list_remove_item(self->parent->child_list, i); - } - } - if (self->string_list != 0) /* for combo */ - { - list_delete(self->string_list); - } - if (self->data_list != 0) /* for combo */ - { - for (i = 0; i < self->data_list->count; i++) - { - mod_data = (struct xrdp_mod_data*)list_get_item(self->data_list, i); - if (mod_data != 0) - { - list_delete(mod_data->names); - list_delete(mod_data->values); - } - } - list_delete(self->data_list); - } - if (!self->do_not_free_data) - { - g_free(self->data); - } - g_free(self->caption1); - g_free(self); + + g_free(self->caption1); + g_free(self); } /*****************************************************************************/ -struct xrdp_bitmap* APP_CC -xrdp_bitmap_get_child_by_id(struct xrdp_bitmap* self, int id) +struct xrdp_bitmap *APP_CC +xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id) { - int i = 0; - struct xrdp_bitmap* b = (struct xrdp_bitmap *)NULL; + int i = 0; + struct xrdp_bitmap *b = (struct xrdp_bitmap *)NULL; - for (i = 0; i < self->child_list->count; i++) - { - b = (struct xrdp_bitmap*)list_get_item(self->child_list, i); - if (b->id == id) + for (i = 0; i < self->child_list->count; i++) { - return b; + b = (struct xrdp_bitmap *)list_get_item(self->child_list, i); + + if (b->id == id) + { + return b; + } } - } - return 0; + + return 0; } /*****************************************************************************/ /* if focused is true focus this window else unfocus it */ /* returns error */ int APP_CC -xrdp_bitmap_set_focus(struct xrdp_bitmap* self, int focused) +xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused) { - struct xrdp_painter* painter = (struct xrdp_painter *)NULL; + struct xrdp_painter *painter = (struct xrdp_painter *)NULL; - if (self == 0) - { + if (self == 0) + { + return 0; + } + + if (self->type != WND_TYPE_WND) /* 1 */ + { + return 0; + } + + painter = xrdp_painter_create(self->wm, self->wm->session); + xrdp_painter_font_needed(painter); + xrdp_painter_begin_update(painter); + + if (focused) + { + /* active title bar */ + painter->fg_color = self->wm->blue; + xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); + painter->fg_color = self->wm->white; + } + else + { + /* inactive title bar */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); + painter->fg_color = self->wm->black; + } + + xrdp_painter_draw_text(painter, self, 4, 4, self->caption1); + xrdp_painter_end_update(painter); + xrdp_painter_delete(painter); return 0; - } - if (self->type != WND_TYPE_WND) /* 1 */ - { - return 0; - } - painter = xrdp_painter_create(self->wm, self->wm->session); - xrdp_painter_font_needed(painter); - xrdp_painter_begin_update(painter); - if (focused) - { - /* active title bar */ - painter->fg_color = self->wm->blue; - xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); - painter->fg_color = self->wm->white; - } - else - { - /* inactive title bar */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); - painter->fg_color = self->wm->black; - } - xrdp_painter_draw_text(painter, self, 4, 4, self->caption1); - xrdp_painter_end_update(painter); - xrdp_painter_delete(painter); - return 0; } /*****************************************************************************/ static int APP_CC -xrdp_bitmap_get_index(struct xrdp_bitmap* self, int* palette, int color) +xrdp_bitmap_get_index(struct xrdp_bitmap *self, int *palette, int color) { - int r = 0; - int g = 0; - int b = 0; + int r = 0; + int g = 0; + int b = 0; - r = (color & 0xff0000) >> 16; - g = (color & 0x00ff00) >> 8; - b = (color & 0x0000ff) >> 0; - r = (r >> 5) << 0; - g = (g >> 5) << 3; - b = (b >> 6) << 6; - return (b | g | r); + r = (color & 0xff0000) >> 16; + g = (color & 0x00ff00) >> 8; + b = (color & 0x0000ff) >> 0; + r = (r >> 5) << 0; + g = (g >> 5) << 3; + b = (b >> 6) << 6; + return (b | g | r); } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_bitmap_resize(struct xrdp_bitmap* self, int width, int height) +xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height) { - int Bpp = 0; + int Bpp = 0; - if ((width == self->width) && (height == self->height)) - { + if ((width == self->width) && (height == self->height)) + { + return 0; + } + + if (self->do_not_free_data) + { + return 1; + } + + self->width = width; + self->height = height; + Bpp = 4; + + switch (self->bpp) + { + case 8: + Bpp = 1; + break; + case 15: + Bpp = 2; + break; + case 16: + Bpp = 2; + break; + } + + g_free(self->data); + self->data = (char *)g_malloc(width * height * Bpp, 0); + self->line_size = width * Bpp; return 0; - } - if (self->do_not_free_data) - { - return 1; - } - self->width = width; - self->height = height; - Bpp = 4; - switch (self->bpp) - { - case 8: Bpp = 1; break; - case 15: Bpp = 2; break; - case 16: Bpp = 2; break; - } - g_free(self->data); - self->data = (char*)g_malloc(width * height * Bpp, 0); - self->line_size = width * Bpp; - return 0; } /*****************************************************************************/ @@ -333,1428 +376,1569 @@ xrdp_bitmap_resize(struct xrdp_bitmap* self, int width, int height) /* return 0 ok */ /* return 1 error */ int APP_CC -xrdp_bitmap_load(struct xrdp_bitmap* self, const char* filename, int* palette) +xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, int *palette) { - int fd = 0; - int i = 0; - int j = 0; - int k = 0; - int color = 0; - int size = 0; - int palette1[256]; - char type1[4]; - struct xrdp_bmp_header header; - struct stream* s = (struct stream *)NULL; + int fd = 0; + int i = 0; + int j = 0; + int k = 0; + int color = 0; + int size = 0; + int palette1[256]; + char type1[4]; + struct xrdp_bmp_header header; + struct stream *s = (struct stream *)NULL; - g_memset(palette1,0,sizeof(int) * 256); - g_memset(type1,0,sizeof(char) * 4); - g_memset(&header,0,sizeof(struct xrdp_bmp_header)); + g_memset(palette1, 0, sizeof(int) * 256); + g_memset(type1, 0, sizeof(char) * 4); + g_memset(&header, 0, sizeof(struct xrdp_bmp_header)); - if (!g_file_exist(filename)) - { - log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " - "does not exist", filename); - return 1; - } - s = (struct stream *)NULL; - fd = g_file_open(filename); - if (fd != -1) - { - /* read file type */ - if (g_file_read(fd, type1, 2) != 2) + if (!g_file_exist(filename)) { - log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " - "read error", filename); - g_file_close(fd); - return 1; + log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " + "does not exist", filename); + return 1; } - if ((type1[0] != 'B') || (type1[1] != 'M')) + + s = (struct stream *)NULL; + fd = g_file_open(filename); + + if (fd != -1) { - log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " - "not BMP file", filename); - g_file_close(fd); - return 1; + /* read file type */ + if (g_file_read(fd, type1, 2) != 2) + { + log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " + "read error", filename); + g_file_close(fd); + return 1; + } + + if ((type1[0] != 'B') || (type1[1] != 'M')) + { + log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " + "not BMP file", filename); + g_file_close(fd); + return 1; + } + + /* read file size */ + make_stream(s); + init_stream(s, 8192); + g_file_read(fd, s->data, 4); + in_uint32_le(s, size); + /* read bmp header */ + g_file_seek(fd, 14); + init_stream(s, 8192); + g_file_read(fd, s->data, 40); /* size better be 40 */ + in_uint32_le(s, header.size); + in_uint32_le(s, header.image_width); + in_uint32_le(s, header.image_height); + in_uint16_le(s, header.planes); + in_uint16_le(s, header.bit_count); + in_uint32_le(s, header.compression); + in_uint32_le(s, header.image_size); + in_uint32_le(s, header.x_pels_per_meter); + in_uint32_le(s, header.y_pels_per_meter); + in_uint32_le(s, header.clr_used); + in_uint32_le(s, header.clr_important); + + if ((header.bit_count != 4) && (header.bit_count != 8) && + (header.bit_count != 24)) + { + log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " + "bad bpp %d", filename, header.bit_count); + free_stream(s); + g_file_close(fd); + return 1; + } + + if (header.bit_count == 24) /* 24 bit bitmap */ + { + g_file_seek(fd, 14 + header.size); + xrdp_bitmap_resize(self, header.image_width, header.image_height); + size = header.image_width * header.image_height * 3; + init_stream(s, size); + + /* read data */ + for (i = header.image_height - 1; i >= 0; i--) + { + size = header.image_width * 3; + k = g_file_read(fd, s->data + i * size, size); + + if (k != size) + { + log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap " + "file [%s] read", filename); + } + } + + for (i = 0; i < self->height; i++) + { + for (j = 0; j < self->width; j++) + { + in_uint8(s, k); + color = k; + in_uint8(s, k); + color |= k << 8; + in_uint8(s, k); + color |= k << 16; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, i, color); + } + } + } + else if (header.bit_count == 8) /* 8 bit bitmap */ + { + /* read palette */ + g_file_seek(fd, 14 + header.size); + init_stream(s, 8192); + g_file_read(fd, s->data, header.clr_used * sizeof(int)); + + for (i = 0; i < header.clr_used; i++) + { + in_uint32_le(s, palette1[i]); + } + + xrdp_bitmap_resize(self, header.image_width, header.image_height); + size = header.image_width * header.image_height; + init_stream(s, size); + + /* read data */ + for (i = header.image_height - 1; i >= 0; i--) + { + size = header.image_width; + k = g_file_read(fd, s->data + i * size, size); + + if (k != size) + { + log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap " + "file [%s] read", filename); + } + } + + for (i = 0; i < self->height; i++) + { + for (j = 0; j < self->width; j++) + { + in_uint8(s, k); + color = palette1[k]; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, i, color); + } + } + } + else if (header.bit_count == 4) /* 4 bit bitmap */ + { + /* read palette */ + g_file_seek(fd, 14 + header.size); + init_stream(s, 8192); + g_file_read(fd, s->data, header.clr_used * sizeof(int)); + + for (i = 0; i < header.clr_used; i++) + { + in_uint32_le(s, palette1[i]); + } + + xrdp_bitmap_resize(self, header.image_width, header.image_height); + size = (header.image_width * header.image_height) / 2; + init_stream(s, size); + + /* read data */ + for (i = header.image_height - 1; i >= 0; i--) + { + size = header.image_width / 2; + k = g_file_read(fd, s->data + i * size, size); + + if (k != size) + { + log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap " + "file [%s] read", filename); + } + } + + for (i = 0; i < self->height; i++) + { + for (j = 0; j < self->width; j++) + { + if ((j & 1) == 0) + { + in_uint8(s, k); + color = (k >> 4) & 0xf; + } + else + { + color = k & 0xf; + } + + color = palette1[color]; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, i, color); + } + } + } + + g_file_close(fd); + free_stream(s); } - /* read file size */ - make_stream(s); - init_stream(s, 8192); - g_file_read(fd, s->data, 4); - in_uint32_le(s, size); - /* read bmp header */ - g_file_seek(fd, 14); - init_stream(s, 8192); - g_file_read(fd, s->data, 40); /* size better be 40 */ - in_uint32_le(s, header.size); - in_uint32_le(s, header.image_width); - in_uint32_le(s, header.image_height); - in_uint16_le(s, header.planes); - in_uint16_le(s, header.bit_count); - in_uint32_le(s, header.compression); - in_uint32_le(s, header.image_size); - in_uint32_le(s, header.x_pels_per_meter); - in_uint32_le(s, header.y_pels_per_meter); - in_uint32_le(s, header.clr_used); - in_uint32_le(s, header.clr_important); - if ((header.bit_count != 4) && (header.bit_count != 8) && - (header.bit_count != 24)) + else { - log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " - "bad bpp %d", filename, header.bit_count); - free_stream(s); - g_file_close(fd); - return 1; + log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error loading bitmap " + "from file [%s]", filename); + return 1; } - if (header.bit_count == 24) /* 24 bit bitmap */ - { - g_file_seek(fd, 14 + header.size); - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = header.image_width * header.image_height * 3; - init_stream(s, size); - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width * 3; - k = g_file_read(fd, s->data + i * size, size); - if (k != size) - { - log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap " - "file [%s] read", filename); - } - } - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - in_uint8(s, k); - color = k; - in_uint8(s, k); - color |= k << 8; - in_uint8(s, k); - color |= k << 16; - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - xrdp_bitmap_set_pixel(self, j, i, color); - } - } - } - else if (header.bit_count == 8) /* 8 bit bitmap */ - { - /* read palette */ - g_file_seek(fd, 14 + header.size); - init_stream(s, 8192); - g_file_read(fd, s->data, header.clr_used * sizeof(int)); - for (i = 0; i < header.clr_used; i++) - { - in_uint32_le(s, palette1[i]); - } - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = header.image_width * header.image_height; - init_stream(s, size); - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width; - k = g_file_read(fd, s->data + i * size, size); - if (k != size) - { - log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap " - "file [%s] read", filename); - } - } - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - in_uint8(s, k); - color = palette1[k]; - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - xrdp_bitmap_set_pixel(self, j, i, color); - } - } - } - else if (header.bit_count == 4) /* 4 bit bitmap */ - { - /* read palette */ - g_file_seek(fd, 14 + header.size); - init_stream(s, 8192); - g_file_read(fd, s->data, header.clr_used * sizeof(int)); - for (i = 0; i < header.clr_used; i++) - { - in_uint32_le(s, palette1[i]); - } - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = (header.image_width * header.image_height) / 2; - init_stream(s, size); - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width / 2; - k = g_file_read(fd, s->data + i * size, size); - if (k != size) - { - log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap " - "file [%s] read", filename); - } - } - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - if ((j & 1) == 0) - { - in_uint8(s, k); - color = (k >> 4) & 0xf; - } - else - { - color = k & 0xf; - } - color = palette1[color]; - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - xrdp_bitmap_set_pixel(self, j, i, color); - } - } - } - g_file_close(fd); - free_stream(s); - } - else - { - log_message(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error loading bitmap " - "from file [%s]", filename); - return 1; - } - return 0; + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_bitmap_get_pixel(struct xrdp_bitmap* self, int x, int y) +xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y) { - if (self == 0) - { + if (self == 0) + { + return 0; + } + + if (self->data == 0) + { + return 0; + } + + if (x >= 0 && x < self->width && y >= 0 && y < self->height) + { + if (self->bpp == 8) + { + return GETPIXEL8(self->data, x, y, self->width); + } + else if (self->bpp == 15 || self->bpp == 16) + { + return GETPIXEL16(self->data, x, y, self->width); + } + else if (self->bpp == 24) + { + return GETPIXEL32(self->data, x, y, self->width); + } + } + return 0; - } - if (self->data == 0) - { - return 0; - } - if (x >= 0 && x < self->width && y >= 0 && y < self->height) - { - if (self->bpp == 8) - { - return GETPIXEL8(self->data, x, y, self->width); - } - else if (self->bpp == 15 || self->bpp == 16) - { - return GETPIXEL16(self->data, x, y, self->width); - } - else if (self->bpp == 24) - { - return GETPIXEL32(self->data, x, y, self->width); - } - } - return 0; } /*****************************************************************************/ int APP_CC -xrdp_bitmap_set_pixel(struct xrdp_bitmap* self, int x, int y, int pixel) +xrdp_bitmap_set_pixel(struct xrdp_bitmap *self, int x, int y, int pixel) { - if (self == 0) - { + if (self == 0) + { + return 0; + } + + if (self->data == 0) + { + return 0; + } + + if (x >= 0 && x < self->width && y >= 0 && y < self->height) + { + if (self->bpp == 8) + { + SETPIXEL8(self->data, x, y, self->width, pixel); + } + else if (self->bpp == 15 || self->bpp == 16) + { + SETPIXEL16(self->data, x, y, self->width, pixel); + } + else if (self->bpp == 24) + { + SETPIXEL32(self->data, x, y, self->width, pixel); + } + } + return 0; - } - if (self->data == 0) - { - return 0; - } - if (x >= 0 && x < self->width && y >= 0 && y < self->height) - { - if (self->bpp == 8) - { - SETPIXEL8(self->data, x, y, self->width, pixel); - } - else if (self->bpp == 15 || self->bpp == 16) - { - SETPIXEL16(self->data, x, y, self->width, pixel); - } - else if (self->bpp == 24) - { - SETPIXEL32(self->data, x, y, self->width, pixel); - } - } - return 0; } /*****************************************************************************/ /* copy part of self at x, y to 0, 0 in dest */ /* returns error */ int APP_CC -xrdp_bitmap_copy_box(struct xrdp_bitmap* self, - struct xrdp_bitmap* dest, +xrdp_bitmap_copy_box(struct xrdp_bitmap *self, + struct xrdp_bitmap *dest, int x, int y, int cx, int cy) { - int i = 0; - int j = 0; - int destx = 0; - int desty = 0; - int pixel = 0; + int i = 0; + int j = 0; + int destx = 0; + int desty = 0; + int pixel = 0; - if (self == 0) - { - return 1; - } - if (dest == 0) - { - return 1; - } - if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE) - { - return 1; - } - if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE) - { - return 1; - } - if (self->bpp != dest->bpp) - { - return 1; - } - destx = 0; - desty = 0; - if (!check_bounds(self, &x, &y, &cx, &cy)) - { - return 1; - } - if (!check_bounds(dest, &destx, &desty, &cx, &cy)) - { - return 1; - } - if (self->bpp == 24) - { - for (i = 0; i < cy; i++) + if (self == 0) { - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL32(self->data, j + x, i + y, self->width); - SETPIXEL32(dest->data, j + destx, i + desty, dest->width, pixel); - } + return 1; } - } - else if (self->bpp == 15 || self->bpp == 16) - { - for (i = 0; i < cy; i++) + + if (dest == 0) { - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL16(self->data, j + x, i + y, self->width); - SETPIXEL16(dest->data, j + destx, i + desty, dest->width, pixel); - } + return 1; } - } - else if (self->bpp == 8) - { - for (i = 0; i < cy; i++) + + if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE) { - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL8(self->data, j + x, i + y, self->width); - SETPIXEL8(dest->data, j + destx, i + desty, dest->width, pixel); - } + return 1; } - } - else - { - return 1; - } - return 0; + + if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE) + { + return 1; + } + + if (self->bpp != dest->bpp) + { + return 1; + } + + destx = 0; + desty = 0; + + if (!check_bounds(self, &x, &y, &cx, &cy)) + { + return 1; + } + + if (!check_bounds(dest, &destx, &desty, &cx, &cy)) + { + return 1; + } + + if (self->bpp == 24) + { + for (i = 0; i < cy; i++) + { + for (j = 0; j < cx; j++) + { + pixel = GETPIXEL32(self->data, j + x, i + y, self->width); + SETPIXEL32(dest->data, j + destx, i + desty, dest->width, pixel); + } + } + } + else if (self->bpp == 15 || self->bpp == 16) + { + for (i = 0; i < cy; i++) + { + for (j = 0; j < cx; j++) + { + pixel = GETPIXEL16(self->data, j + x, i + y, self->width); + SETPIXEL16(dest->data, j + destx, i + desty, dest->width, pixel); + } + } + } + else if (self->bpp == 8) + { + for (i = 0; i < cy; i++) + { + for (j = 0; j < cx; j++) + { + pixel = GETPIXEL8(self->data, j + x, i + y, self->width); + SETPIXEL8(dest->data, j + destx, i + desty, dest->width, pixel); + } + } + } + else + { + return 1; + } + + return 0; } /*****************************************************************************/ /* copy part of self at x, y to 0, 0 in dest */ /* returns error */ int APP_CC -xrdp_bitmap_copy_box_with_crc(struct xrdp_bitmap* self, - struct xrdp_bitmap* dest, +xrdp_bitmap_copy_box_with_crc(struct xrdp_bitmap *self, + struct xrdp_bitmap *dest, int x, int y, int cx, int cy) { - int i = 0; - int j = 0; - int destx = 0; - int desty = 0; - int pixel = 0; - int crc = 0; - int incs = 0; - int incd = 0; - unsigned char* s8 = (unsigned char *)NULL; - unsigned char* d8 = (unsigned char *)NULL; - unsigned short* s16 = (unsigned short *)NULL; - unsigned short* d16 = (unsigned short *)NULL; + int i = 0; + int j = 0; + int destx = 0; + int desty = 0; + int pixel = 0; + int crc = 0; + int incs = 0; + int incd = 0; + unsigned char *s8 = (unsigned char *)NULL; + unsigned char *d8 = (unsigned char *)NULL; + unsigned short *s16 = (unsigned short *)NULL; + unsigned short *d16 = (unsigned short *)NULL; - if (self == 0) - { - return 1; - } - if (dest == 0) - { - return 1; - } - if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE) - { - return 1; - } - if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE) - { - return 1; - } - if (self->bpp != dest->bpp) - { - return 1; - } - destx = 0; - desty = 0; - if (!check_bounds(self, &x, &y, &cx, &cy)) - { - return 1; - } - if (!check_bounds(dest, &destx, &desty, &cx, &cy)) - { - return 1; - } - CRC_START(crc); - if (self->bpp == 24) - { - for (i = 0; i < cy; i++) + if (self == 0) { - for (j = 0; j < cx; j++) - { - pixel = GETPIXEL32(self->data, j + x, i + y, self->width); - CRC_PASS(pixel, crc); - CRC_PASS(pixel >> 8, crc); - CRC_PASS(pixel >> 16, crc); - SETPIXEL32(dest->data, j + destx, i + desty, dest->width, pixel); - } + return 1; } - } - else if (self->bpp == 15 || self->bpp == 16) - { - s16 = ((unsigned short*)(self->data)) + (self->width * y + x); - d16 = ((unsigned short*)(dest->data)) + (dest->width * desty + destx); - incs = self->width - cx; - incd = dest->width - cx; - for (i = 0; i < cy; i++) + + if (dest == 0) { - for (j = 0; j < cx; j++) - { - pixel = *s16; - CRC_PASS(pixel, crc); - CRC_PASS(pixel >> 8, crc); - *d16 = pixel; - s16++; - d16++; - } - s16 += incs; - d16 += incd; + return 1; } - } - else if (self->bpp == 8) - { - s8 = ((unsigned char*)(self->data)) + (self->width * y + x); - d8 = ((unsigned char*)(dest->data)) + (dest->width * desty + destx); - incs = self->width - cx; - incd = dest->width - cx; - for (i = 0; i < cy; i++) + + if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE) { - for (j = 0; j < cx; j++) - { - pixel = *s8; - CRC_PASS(pixel, crc); - *d8 = pixel; - s8++; - d8++; - } - s8 += incs; - d8 += incd; + return 1; } - } - else - { - return 1; - } - CRC_END(crc); - dest->crc = crc; - return 0; + + if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE) + { + return 1; + } + + if (self->bpp != dest->bpp) + { + return 1; + } + + destx = 0; + desty = 0; + + if (!check_bounds(self, &x, &y, &cx, &cy)) + { + return 1; + } + + if (!check_bounds(dest, &destx, &desty, &cx, &cy)) + { + return 1; + } + + CRC_START(crc); + + if (self->bpp == 24) + { + for (i = 0; i < cy; i++) + { + for (j = 0; j < cx; j++) + { + pixel = GETPIXEL32(self->data, j + x, i + y, self->width); + CRC_PASS(pixel, crc); + CRC_PASS(pixel >> 8, crc); + CRC_PASS(pixel >> 16, crc); + SETPIXEL32(dest->data, j + destx, i + desty, dest->width, pixel); + } + } + } + else if (self->bpp == 15 || self->bpp == 16) + { + s16 = ((unsigned short *)(self->data)) + (self->width * y + x); + d16 = ((unsigned short *)(dest->data)) + (dest->width * desty + destx); + incs = self->width - cx; + incd = dest->width - cx; + + for (i = 0; i < cy; i++) + { + for (j = 0; j < cx; j++) + { + pixel = *s16; + CRC_PASS(pixel, crc); + CRC_PASS(pixel >> 8, crc); + *d16 = pixel; + s16++; + d16++; + } + + s16 += incs; + d16 += incd; + } + } + else if (self->bpp == 8) + { + s8 = ((unsigned char *)(self->data)) + (self->width * y + x); + d8 = ((unsigned char *)(dest->data)) + (dest->width * desty + destx); + incs = self->width - cx; + incd = dest->width - cx; + + for (i = 0; i < cy; i++) + { + for (j = 0; j < cx; j++) + { + pixel = *s8; + CRC_PASS(pixel, crc); + *d8 = pixel; + s8++; + d8++; + } + + s8 += incs; + d8 += incd; + } + } + else + { + return 1; + } + + CRC_END(crc); + dest->crc = crc; + return 0; } /*****************************************************************************/ /* returns true if they are the same, else returns false */ int APP_CC -xrdp_bitmap_compare(struct xrdp_bitmap* self, - struct xrdp_bitmap* b) +xrdp_bitmap_compare(struct xrdp_bitmap *self, + struct xrdp_bitmap *b) { - if (self == 0) - { + if (self == 0) + { + return 0; + } + + if (b == 0) + { + return 0; + } + + if (self->bpp != b->bpp) + { + return 0; + } + + if (self->width != b->width) + { + return 0; + } + + if (self->height != b->height) + { + return 0; + } + + if (g_memcmp(self->data, b->data, b->height * b->line_size) == 0) + { + return 1; + } + return 0; - } - if (b == 0) - { - return 0; - } - if (self->bpp != b->bpp) - { - return 0; - } - if (self->width != b->width) - { - return 0; - } - if (self->height != b->height) - { - return 0; - } - if (g_memcmp(self->data, b->data, b->height * b->line_size) == 0) - { - return 1; - } - return 0; } /*****************************************************************************/ /* returns true if they are the same, else returns false */ int APP_CC -xrdp_bitmap_compare_with_crc(struct xrdp_bitmap* self, - struct xrdp_bitmap* b) +xrdp_bitmap_compare_with_crc(struct xrdp_bitmap *self, + struct xrdp_bitmap *b) { - if (self == 0) - { + if (self == 0) + { + return 0; + } + + if (b == 0) + { + return 0; + } + + if (self->bpp != b->bpp) + { + return 0; + } + + if (self->width != b->width) + { + return 0; + } + + if (self->height != b->height) + { + return 0; + } + + if (self->crc == b->crc) + { + return 1; + } + return 0; - } - if (b == 0) - { - return 0; - } - if (self->bpp != b->bpp) - { - return 0; - } - if (self->width != b->width) - { - return 0; - } - if (self->height != b->height) - { - return 0; - } - if (self->crc == b->crc) - { - return 1; - } - return 0; } /*****************************************************************************/ static int APP_CC -xrdp_bitmap_draw_focus_box(struct xrdp_bitmap* self, - struct xrdp_painter* painter, +xrdp_bitmap_draw_focus_box(struct xrdp_bitmap *self, + struct xrdp_painter *painter, int x, int y, int cx, int cy) { - painter->rop = 0xf0; - xrdp_painter_begin_update(painter); - painter->use_clip = 0; - painter->mix_mode = 1; - painter->brush.pattern[0] = 0xaa; - painter->brush.pattern[1] = 0x55; - painter->brush.pattern[2] = 0xaa; - painter->brush.pattern[3] = 0x55; - painter->brush.pattern[4] = 0xaa; - painter->brush.pattern[5] = 0x55; - painter->brush.pattern[6] = 0xaa; - painter->brush.pattern[7] = 0x55; - painter->brush.x_orgin = x; - painter->brush.x_orgin = x; - painter->brush.style = 3; - painter->fg_color = self->wm->black; - painter->bg_color = self->parent->bg_color; - /* top */ - xrdp_painter_fill_rect(painter, self, x, y, cx, 1); - /* bottom */ - xrdp_painter_fill_rect(painter, self, x, y + (cy - 1), cx, 1); - /* left */ - xrdp_painter_fill_rect(painter, self, x, y + 1, 1, cy - 2); - /* right */ - xrdp_painter_fill_rect(painter, self, x + (cx - 1), y + 1, 1, cy - 2); - xrdp_painter_end_update(painter); - painter->rop = 0xcc; - painter->mix_mode = 0; - return 0; + painter->rop = 0xf0; + xrdp_painter_begin_update(painter); + painter->use_clip = 0; + painter->mix_mode = 1; + painter->brush.pattern[0] = 0xaa; + painter->brush.pattern[1] = 0x55; + painter->brush.pattern[2] = 0xaa; + painter->brush.pattern[3] = 0x55; + painter->brush.pattern[4] = 0xaa; + painter->brush.pattern[5] = 0x55; + painter->brush.pattern[6] = 0xaa; + painter->brush.pattern[7] = 0x55; + painter->brush.x_orgin = x; + painter->brush.x_orgin = x; + painter->brush.style = 3; + painter->fg_color = self->wm->black; + painter->bg_color = self->parent->bg_color; + /* top */ + xrdp_painter_fill_rect(painter, self, x, y, cx, 1); + /* bottom */ + xrdp_painter_fill_rect(painter, self, x, y + (cy - 1), cx, 1); + /* left */ + xrdp_painter_fill_rect(painter, self, x, y + 1, 1, cy - 2); + /* right */ + xrdp_painter_fill_rect(painter, self, x + (cx - 1), y + 1, 1, cy - 2); + xrdp_painter_end_update(painter); + painter->rop = 0xcc; + painter->mix_mode = 0; + return 0; } /*****************************************************************************/ /* x and y are in relation to self for 0, 0 is the top left of the control */ static int APP_CC -xrdp_bitmap_draw_button(struct xrdp_bitmap* self, - struct xrdp_painter* painter, +xrdp_bitmap_draw_button(struct xrdp_bitmap *self, + struct xrdp_painter *painter, int x, int y, int w, int h, int down) { - if (down) - { - /* gray box */ - painter->fg_color = self->wm->grey; - xrdp_painter_fill_rect(painter, self, x, y, w, h); - /* black top line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, x, y, w, 1); - /* black left line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, x, y, 1, h); - /* dark grey top line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, x + 1, y + 1, w - 2, 1); - /* dark grey left line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, x + 1, y + 1, 1, h - 2); - /* dark grey bottom line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, x + 1, y + (h - 2), w - 1, 1); - /* dark grey right line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, x + (w - 2), y + 1, 1, h - 1); - /* black bottom line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, x, y + (h - 1), w, 1); - /* black right line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, x + (w - 1), y, 1, h); - } - else - { - /* gray box */ - painter->fg_color = self->wm->grey; - xrdp_painter_fill_rect(painter, self, x, y, w, h); - /* white top line */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, x, y, w, 1); - /* white left line */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, x, y, 1, h); - /* dark grey bottom line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, x + 1, y + (h - 2), w - 1, 1); - /* dark grey right line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, (x + w) - 2, y + 1, 1, h - 1); - /* black bottom line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, x, y + (h - 1), w, 1); - /* black right line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, x + (w - 1), y, 1, h); - } - return 0; + if (down) + { + /* gray box */ + painter->fg_color = self->wm->grey; + xrdp_painter_fill_rect(painter, self, x, y, w, h); + /* black top line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, x, y, w, 1); + /* black left line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, x, y, 1, h); + /* dark grey top line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, x + 1, y + 1, w - 2, 1); + /* dark grey left line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, x + 1, y + 1, 1, h - 2); + /* dark grey bottom line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, x + 1, y + (h - 2), w - 1, 1); + /* dark grey right line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, x + (w - 2), y + 1, 1, h - 1); + /* black bottom line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, x, y + (h - 1), w, 1); + /* black right line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, x + (w - 1), y, 1, h); + } + else + { + /* gray box */ + painter->fg_color = self->wm->grey; + xrdp_painter_fill_rect(painter, self, x, y, w, h); + /* white top line */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, x, y, w, 1); + /* white left line */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, x, y, 1, h); + /* dark grey bottom line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, x + 1, y + (h - 2), w - 1, 1); + /* dark grey right line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, (x + w) - 2, y + 1, 1, h - 1); + /* black bottom line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, x, y + (h - 1), w, 1); + /* black right line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, x + (w - 1), y, 1, h); + } + + return 0; } /*****************************************************************************/ /* nil for rect means the whole thing */ /* returns error */ int APP_CC -xrdp_bitmap_invalidate(struct xrdp_bitmap* self, struct xrdp_rect* rect) +xrdp_bitmap_invalidate(struct xrdp_bitmap *self, struct xrdp_rect *rect) { - int i; - int w; - int h; - int x; - int y; - struct xrdp_bitmap* b; - struct xrdp_rect r1; - struct xrdp_rect r2; - struct xrdp_painter* painter; - twchar wtext[256]; - char text[256]; - char* p; + int i; + int w; + int h; + int x; + int y; + struct xrdp_bitmap *b; + struct xrdp_rect r1; + struct xrdp_rect r2; + struct xrdp_painter *painter; + twchar wtext[256]; + char text[256]; + char *p; - if (self == 0) /* if no bitmap */ - { - return 0; - } - if (self->type == WND_TYPE_BITMAP) /* if 0, bitmap, leave */ - { - return 0; - } - painter = xrdp_painter_create(self->wm, self->wm->session); - xrdp_painter_font_needed(painter); - painter->rop = 0xcc; /* copy */ - if (rect == 0) - { - painter->use_clip = 0; - } - else - { - if (ISRECTEMPTY(*rect)) + if (self == 0) /* if no bitmap */ { - xrdp_painter_delete(painter); - return 0; + return 0; } - painter->clip = *rect; - painter->use_clip = &painter->clip; - } - xrdp_painter_begin_update(painter); - if (self->type == WND_TYPE_WND) /* 1 */ - { - /* draw grey background */ - painter->fg_color = self->bg_color; - xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); - /* top white line */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 2, 1); - /* left white line */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 2); - /* bottom dark grey line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, 1, self->height - 2, - self->width - 2, 1); - /* right dark grey line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, self->width - 2, 1, 1, - self->height - 2); - /* bottom black line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, 0, self->height - 1, - self->width, 1); - /* right black line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, self->width - 1, 0, - 1, self->height); - if (self->wm->focused_window == self) + + if (self->type == WND_TYPE_BITMAP) /* if 0, bitmap, leave */ { - /* active title bar */ - painter->fg_color = self->wm->blue; - xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); - painter->fg_color = self->wm->white; + return 0; } - else - { - /* inactive title bar */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); - painter->fg_color = self->wm->black; - } - xrdp_painter_draw_text(painter, self, 4, 4, self->caption1); - } - else if (self->type == WND_TYPE_SCREEN) /* 2 */ - { - if (self->wm->mm->mod != 0) - { - if (self->wm->mm->mod->mod_event != 0) - { - if (rect != 0) - { - x = rect->left; - y = rect->top; - w = rect->right - rect->left; - h = rect->bottom - rect->top; - if (check_bounds(self->wm->screen, &x, &y, &w, &h)) - { - self->wm->mm->mod->mod_event(self->wm->mm->mod, WM_INVALIDATE, - MAKELONG(y, x), MAKELONG(h, w), - 0, 0); - } - } - else - { - x = 0; - y = 0; - w = self->wm->screen->width; - h = self->wm->screen->height; - self->wm->mm->mod->mod_event(self->wm->mm->mod, WM_INVALIDATE, - MAKELONG(y, x), MAKELONG(h, w), - 0, 0); - } - } - } - else - { - painter->fg_color = self->bg_color; - xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); - } - } - else if (self->type == WND_TYPE_BUTTON) /* 3 */ - { - if (self->state == BUTTON_STATE_UP) /* 0 */ - { - xrdp_bitmap_draw_button(self, painter, 0, 0, - self->width, self->height, 0); - w = xrdp_painter_text_width(painter, self->caption1); - h = xrdp_painter_text_height(painter, self->caption1); - painter->fg_color = self->wm->black; - xrdp_painter_draw_text(painter, self, self->width / 2 - w / 2, - self->height / 2 - h / 2, self->caption1); - if (self->parent != 0) - { - if (self->wm->focused_window == self->parent) - { - if (self->parent->focused_control == self) - { - xrdp_bitmap_draw_focus_box(self, painter, 4, 4, self->width - 8, - self->height - 8); - } - } - } - } - else if (self->state == BUTTON_STATE_DOWN) /* 1 */ - { - xrdp_bitmap_draw_button(self, painter, 0, 0, - self->width, self->height, 1); - w = xrdp_painter_text_width(painter, self->caption1); - h = xrdp_painter_text_height(painter, self->caption1); - painter->fg_color = self->wm->black; - xrdp_painter_draw_text(painter, self, (self->width / 2 - w / 2) + 1, - (self->height / 2 - h / 2) + 1, self->caption1); - if (self->parent != 0) - if (self->wm->focused_window == self->parent) - if (self->parent->focused_control == self) - xrdp_bitmap_draw_focus_box(self, painter, 4, 4, self->width - 8, - self->height - 8); - } - } - else if (self->type == WND_TYPE_IMAGE) /* 4 */ - { - xrdp_painter_copy(painter, self, self, 0, 0, self->width, - self->height, 0, 0); - } - else if (self->type == WND_TYPE_EDIT) /* 5 */ - { - /* draw gray box */ - painter->fg_color = self->wm->grey; - xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); - /* main white background */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, - self->height - 3); - /* dark grey top line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, 0, 0, self->width, 1); - /* dark grey left line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, 0, 0, 1, self->height); - /* white bottom line */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, 0, self->height- 1, self->width, 1); - /* white right line */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, self->width - 1, 0, 1, self->height); - /* black left line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 3); - /* black top line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, 1); - /* draw text */ - painter->fg_color = self->wm->black; - if (self->password_char != 0) - { - i = g_mbstowcs(0, self->caption1, 0); - g_memset(text, self->password_char, i); - text[i] = 0; - xrdp_painter_draw_text(painter, self, 4, 2, text); - } - else - { - xrdp_painter_draw_text(painter, self, 4, 2, self->caption1); - } - /* draw xor box(cursor) */ - if (self->parent != 0) - { - if (self->parent->focused_control == self) - { - if (self->password_char != 0) - { - wchar_repeat(wtext, 255, self->password_char, self->edit_pos); - wtext[self->edit_pos] = 0; - g_wcstombs(text, wtext, 255); - } - else - { - g_mbstowcs(wtext, self->caption1, 255); - wtext[self->edit_pos] = 0; - g_wcstombs(text, wtext, 255); - } - w = xrdp_painter_text_width(painter, text); - painter->fg_color = self->wm->white; - painter->rop = 0x5a; - xrdp_painter_fill_rect(painter, self, 4 + w, 3, 2, self->height - 6); - } - } - /* reset rop back */ - painter->rop = 0xcc; - } - else if (self->type == WND_TYPE_LABEL) /* 6 */ - { - painter->fg_color = self->wm->black; - xrdp_painter_draw_text(painter, self, 0, 0, self->caption1); - } - else if (self->type == WND_TYPE_COMBO) /* 7 combo box */ - { - /* draw gray box */ - painter->fg_color = self->wm->grey; - xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); - /* white background */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, - self->height - 3); - if (self->parent->focused_control == self) - { - painter->fg_color = self->wm->dark_blue; - xrdp_painter_fill_rect(painter, self, 3, 3, (self->width - 6) - 18, - self->height - 5); - } - /* dark grey top line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, 0, 0, self->width, 1); - /* dark grey left line */ - painter->fg_color = self->wm->dark_grey; - xrdp_painter_fill_rect(painter, self, 0, 0, 1, self->height); - /* white bottom line */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, 0, self->height- 1, self->width, 1); - /* white right line */ - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, self->width - 1, 0, 1, self->height); - /* black left line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 3); - /* black top line */ - painter->fg_color = self->wm->black; - xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, 1); - /* draw text */ - if (self->parent->focused_control == self) - { - painter->fg_color = self->wm->white; - } - else - { - painter->fg_color = self->wm->black; - } - xrdp_painter_draw_text(painter, self, 4, 2, - (char*)list_get_item(self->string_list, self->item_index)); - /* draw button on right */ - x = self->width - 20; - y = 2; - w = (self->width - x) - 2; - h = self->height - 4; - /* looks better with a background around */ - painter->fg_color = self->wm->grey; - xrdp_painter_fill_rect(painter, self, x, y, w, h); - if (self->state == BUTTON_STATE_UP) /* 0 */ - { - xrdp_bitmap_draw_button(self, painter, x+1, y+1, w-1, h-1, 0); - } - else - { - xrdp_bitmap_draw_button(self, painter, x+1, y+1, w-1, h-1, 1); - } - /* draw the arrow */ - w = w / 2; - x = x + (w / 2) + 1; - h = (h / 2) + 2; - y = y + (h / 2) + 1; - painter->fg_color = self->wm->black; - for (i=w; i>0; i=i-2) - { - xrdp_painter_fill_rect(painter, self, x, y, i, 1); - y++; - x = x + 1; - } - } - else if (self->type == WND_TYPE_SPECIAL) /* 8 special */ - { - if (self->popped_from != 0) - { - /* change height if there are too many items in the list */ - i = xrdp_painter_text_height(painter, "W"); - i = self->popped_from->string_list->count * i; - if (i > self->height) - { - self->height = i; - } - } - painter->fg_color = self->wm->white; - xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); - /* draw the list items */ - if (self->popped_from != 0) - { - y = 0; - for (i = 0; i < self->popped_from->string_list->count; i++) - { - p = (char*)list_get_item(self->popped_from->string_list, i); - h = xrdp_painter_text_height(painter, p); - self->item_height = h; - if (i == self->item_index) - { - painter->fg_color = self->wm->blue; - xrdp_painter_fill_rect(painter, self, 0, y, self->width, h); - painter->fg_color = self->wm->white; - } - else - { - painter->fg_color = self->wm->black; - } - xrdp_painter_draw_text(painter, self, 2, y, p); - y = y + h; - } - } - } - /* notify */ - if (self->notify != 0) - { - self->notify(self, self, WM_PAINT, (long)painter, 0); /* 3 */ - } - /* draw any child windows in the area */ - for (i = 0; i < self->child_list->count; i++) - { - b = (struct xrdp_bitmap*)list_get_item(self->child_list, i); + + painter = xrdp_painter_create(self->wm, self->wm->session); + xrdp_painter_font_needed(painter); + painter->rop = 0xcc; /* copy */ + if (rect == 0) { - xrdp_bitmap_invalidate(b, 0); + painter->use_clip = 0; } else { - MAKERECT(r1, b->left, b->top, b->width, b->height); - if (rect_intersect(rect, &r1, &r2)) - { - RECTOFFSET(r2, -(b->left), -(b->top)); - xrdp_bitmap_invalidate(b, &r2); - } + if (ISRECTEMPTY(*rect)) + { + xrdp_painter_delete(painter); + return 0; + } + + painter->clip = *rect; + painter->use_clip = &painter->clip; } - } - xrdp_painter_end_update(painter); - xrdp_painter_delete(painter); - return 0; + + xrdp_painter_begin_update(painter); + + if (self->type == WND_TYPE_WND) /* 1 */ + { + /* draw grey background */ + painter->fg_color = self->bg_color; + xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); + /* top white line */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 2, 1); + /* left white line */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 2); + /* bottom dark grey line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, 1, self->height - 2, + self->width - 2, 1); + /* right dark grey line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, self->width - 2, 1, 1, + self->height - 2); + /* bottom black line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, 0, self->height - 1, + self->width, 1); + /* right black line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, self->width - 1, 0, + 1, self->height); + + if (self->wm->focused_window == self) + { + /* active title bar */ + painter->fg_color = self->wm->blue; + xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); + painter->fg_color = self->wm->white; + } + else + { + /* inactive title bar */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, 3, 3, self->width - 5, 18); + painter->fg_color = self->wm->black; + } + + xrdp_painter_draw_text(painter, self, 4, 4, self->caption1); + } + else if (self->type == WND_TYPE_SCREEN) /* 2 */ + { + if (self->wm->mm->mod != 0) + { + if (self->wm->mm->mod->mod_event != 0) + { + if (rect != 0) + { + x = rect->left; + y = rect->top; + w = rect->right - rect->left; + h = rect->bottom - rect->top; + + if (check_bounds(self->wm->screen, &x, &y, &w, &h)) + { + self->wm->mm->mod->mod_event(self->wm->mm->mod, WM_INVALIDATE, + MAKELONG(y, x), MAKELONG(h, w), + 0, 0); + } + } + else + { + x = 0; + y = 0; + w = self->wm->screen->width; + h = self->wm->screen->height; + self->wm->mm->mod->mod_event(self->wm->mm->mod, WM_INVALIDATE, + MAKELONG(y, x), MAKELONG(h, w), + 0, 0); + } + } + } + else + { + painter->fg_color = self->bg_color; + xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); + } + } + else if (self->type == WND_TYPE_BUTTON) /* 3 */ + { + if (self->state == BUTTON_STATE_UP) /* 0 */ + { + xrdp_bitmap_draw_button(self, painter, 0, 0, + self->width, self->height, 0); + w = xrdp_painter_text_width(painter, self->caption1); + h = xrdp_painter_text_height(painter, self->caption1); + painter->fg_color = self->wm->black; + xrdp_painter_draw_text(painter, self, self->width / 2 - w / 2, + self->height / 2 - h / 2, self->caption1); + + if (self->parent != 0) + { + if (self->wm->focused_window == self->parent) + { + if (self->parent->focused_control == self) + { + xrdp_bitmap_draw_focus_box(self, painter, 4, 4, self->width - 8, + self->height - 8); + } + } + } + } + else if (self->state == BUTTON_STATE_DOWN) /* 1 */ + { + xrdp_bitmap_draw_button(self, painter, 0, 0, + self->width, self->height, 1); + w = xrdp_painter_text_width(painter, self->caption1); + h = xrdp_painter_text_height(painter, self->caption1); + painter->fg_color = self->wm->black; + xrdp_painter_draw_text(painter, self, (self->width / 2 - w / 2) + 1, + (self->height / 2 - h / 2) + 1, self->caption1); + + if (self->parent != 0) + if (self->wm->focused_window == self->parent) + if (self->parent->focused_control == self) + xrdp_bitmap_draw_focus_box(self, painter, 4, 4, self->width - 8, + self->height - 8); + } + } + else if (self->type == WND_TYPE_IMAGE) /* 4 */ + { + xrdp_painter_copy(painter, self, self, 0, 0, self->width, + self->height, 0, 0); + } + else if (self->type == WND_TYPE_EDIT) /* 5 */ + { + /* draw gray box */ + painter->fg_color = self->wm->grey; + xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); + /* main white background */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, + self->height - 3); + /* dark grey top line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, 0, 0, self->width, 1); + /* dark grey left line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, 0, 0, 1, self->height); + /* white bottom line */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, 0, self->height - 1, self->width, 1); + /* white right line */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, self->width - 1, 0, 1, self->height); + /* black left line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 3); + /* black top line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, 1); + /* draw text */ + painter->fg_color = self->wm->black; + + if (self->password_char != 0) + { + i = g_mbstowcs(0, self->caption1, 0); + g_memset(text, self->password_char, i); + text[i] = 0; + xrdp_painter_draw_text(painter, self, 4, 2, text); + } + else + { + xrdp_painter_draw_text(painter, self, 4, 2, self->caption1); + } + + /* draw xor box(cursor) */ + if (self->parent != 0) + { + if (self->parent->focused_control == self) + { + if (self->password_char != 0) + { + wchar_repeat(wtext, 255, self->password_char, self->edit_pos); + wtext[self->edit_pos] = 0; + g_wcstombs(text, wtext, 255); + } + else + { + g_mbstowcs(wtext, self->caption1, 255); + wtext[self->edit_pos] = 0; + g_wcstombs(text, wtext, 255); + } + + w = xrdp_painter_text_width(painter, text); + painter->fg_color = self->wm->white; + painter->rop = 0x5a; + xrdp_painter_fill_rect(painter, self, 4 + w, 3, 2, self->height - 6); + } + } + + /* reset rop back */ + painter->rop = 0xcc; + } + else if (self->type == WND_TYPE_LABEL) /* 6 */ + { + painter->fg_color = self->wm->black; + xrdp_painter_draw_text(painter, self, 0, 0, self->caption1); + } + else if (self->type == WND_TYPE_COMBO) /* 7 combo box */ + { + /* draw gray box */ + painter->fg_color = self->wm->grey; + xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); + /* white background */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, + self->height - 3); + + if (self->parent->focused_control == self) + { + painter->fg_color = self->wm->dark_blue; + xrdp_painter_fill_rect(painter, self, 3, 3, (self->width - 6) - 18, + self->height - 5); + } + + /* dark grey top line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, 0, 0, self->width, 1); + /* dark grey left line */ + painter->fg_color = self->wm->dark_grey; + xrdp_painter_fill_rect(painter, self, 0, 0, 1, self->height); + /* white bottom line */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, 0, self->height - 1, self->width, 1); + /* white right line */ + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, self->width - 1, 0, 1, self->height); + /* black left line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, 1, 1, 1, self->height - 3); + /* black top line */ + painter->fg_color = self->wm->black; + xrdp_painter_fill_rect(painter, self, 1, 1, self->width - 3, 1); + + /* draw text */ + if (self->parent->focused_control == self) + { + painter->fg_color = self->wm->white; + } + else + { + painter->fg_color = self->wm->black; + } + + xrdp_painter_draw_text(painter, self, 4, 2, + (char *)list_get_item(self->string_list, self->item_index)); + /* draw button on right */ + x = self->width - 20; + y = 2; + w = (self->width - x) - 2; + h = self->height - 4; + /* looks better with a background around */ + painter->fg_color = self->wm->grey; + xrdp_painter_fill_rect(painter, self, x, y, w, h); + + if (self->state == BUTTON_STATE_UP) /* 0 */ + { + xrdp_bitmap_draw_button(self, painter, x + 1, y + 1, w - 1, h - 1, 0); + } + else + { + xrdp_bitmap_draw_button(self, painter, x + 1, y + 1, w - 1, h - 1, 1); + } + + /* draw the arrow */ + w = w / 2; + x = x + (w / 2) + 1; + h = (h / 2) + 2; + y = y + (h / 2) + 1; + painter->fg_color = self->wm->black; + + for (i = w; i > 0; i = i - 2) + { + xrdp_painter_fill_rect(painter, self, x, y, i, 1); + y++; + x = x + 1; + } + } + else if (self->type == WND_TYPE_SPECIAL) /* 8 special */ + { + if (self->popped_from != 0) + { + /* change height if there are too many items in the list */ + i = xrdp_painter_text_height(painter, "W"); + i = self->popped_from->string_list->count * i; + + if (i > self->height) + { + self->height = i; + } + } + + painter->fg_color = self->wm->white; + xrdp_painter_fill_rect(painter, self, 0, 0, self->width, self->height); + + /* draw the list items */ + if (self->popped_from != 0) + { + y = 0; + + for (i = 0; i < self->popped_from->string_list->count; i++) + { + p = (char *)list_get_item(self->popped_from->string_list, i); + h = xrdp_painter_text_height(painter, p); + self->item_height = h; + + if (i == self->item_index) + { + painter->fg_color = self->wm->blue; + xrdp_painter_fill_rect(painter, self, 0, y, self->width, h); + painter->fg_color = self->wm->white; + } + else + { + painter->fg_color = self->wm->black; + } + + xrdp_painter_draw_text(painter, self, 2, y, p); + y = y + h; + } + } + } + + /* notify */ + if (self->notify != 0) + { + self->notify(self, self, WM_PAINT, (long)painter, 0); /* 3 */ + } + + /* draw any child windows in the area */ + for (i = 0; i < self->child_list->count; i++) + { + b = (struct xrdp_bitmap *)list_get_item(self->child_list, i); + + if (rect == 0) + { + xrdp_bitmap_invalidate(b, 0); + } + else + { + MAKERECT(r1, b->left, b->top, b->width, b->height); + + if (rect_intersect(rect, &r1, &r2)) + { + RECTOFFSET(r2, -(b->left), -(b->top)); + xrdp_bitmap_invalidate(b, &r2); + } + } + } + + xrdp_painter_end_update(painter); + xrdp_painter_delete(painter); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_bitmap_def_proc(struct xrdp_bitmap* self, int msg, +xrdp_bitmap_def_proc(struct xrdp_bitmap *self, int msg, int param1, int param2) { - twchar c; - int n; - int i; - int shift; - int ext; - int scan_code; - int num_bytes; - int num_chars; - struct xrdp_bitmap* b; - struct xrdp_bitmap* focus_out_control; + twchar c; + int n; + int i; + int shift; + int ext; + int scan_code; + int num_bytes; + int num_chars; + struct xrdp_bitmap *b; + struct xrdp_bitmap *focus_out_control; - if (self == 0) - { - return 0; - } - if (self->wm == 0) - { - return 0; - } - if (self->type == WND_TYPE_WND) - { - if (msg == WM_KEYDOWN) + if (self == 0) { - scan_code = param1 % 128; - if (scan_code == 15) /* tab */ - { - /* move to next tab stop */ - shift = self->wm->keys[42] || self->wm->keys[54]; - i = -1; - if (self->child_list != 0) + return 0; + } + + if (self->wm == 0) + { + return 0; + } + + if (self->type == WND_TYPE_WND) + { + if (msg == WM_KEYDOWN) { - i = list_index_of(self->child_list, (long)self->focused_control); - } - if (shift) - { - i--; - if (i < 0) - { - i = self->child_list->count - 1; - } - } - else - { - i++; - if (i >= self->child_list->count) - { - i = 0; - } - } - n = self->child_list->count; - b = (struct xrdp_bitmap*)list_get_item(self->child_list, i); - while (b != self->focused_control && b != 0 && n > 0) - { - n--; - if (b->tab_stop) - { - focus_out_control = self->focused_control; - self->focused_control = b; - xrdp_bitmap_invalidate(focus_out_control, 0); - xrdp_bitmap_invalidate(b, 0); - break; - } - if (shift) - { - i--; - if (i < 0) + scan_code = param1 % 128; + + if (scan_code == 15) /* tab */ { - i = self->child_list->count - 1; + /* move to next tab stop */ + shift = self->wm->keys[42] || self->wm->keys[54]; + i = -1; + + if (self->child_list != 0) + { + i = list_index_of(self->child_list, (long)self->focused_control); + } + + if (shift) + { + i--; + + if (i < 0) + { + i = self->child_list->count - 1; + } + } + else + { + i++; + + if (i >= self->child_list->count) + { + i = 0; + } + } + + n = self->child_list->count; + b = (struct xrdp_bitmap *)list_get_item(self->child_list, i); + + while (b != self->focused_control && b != 0 && n > 0) + { + n--; + + if (b->tab_stop) + { + focus_out_control = self->focused_control; + self->focused_control = b; + xrdp_bitmap_invalidate(focus_out_control, 0); + xrdp_bitmap_invalidate(b, 0); + break; + } + + if (shift) + { + i--; + + if (i < 0) + { + i = self->child_list->count - 1; + } + } + else + { + i++; + + if (i >= self->child_list->count) + { + i = 0; + } + } + + b = (struct xrdp_bitmap *)list_get_item(self->child_list, i); + } } - } - else - { - i++; - if (i >= self->child_list->count) + else if (scan_code == 28) /* enter */ { - i = 0; + if (self->default_button != 0) + { + if (self->notify != 0) + { + /* I think this should use def_proc */ + self->notify(self, self->default_button, 1, 0, 0); + return 0; + } + } + } + else if (scan_code == 1) /* esc */ + { + if (self->esc_button != 0) + { + if (self->notify != 0) + { + /* I think this should use def_proc */ + self->notify(self, self->esc_button, 1, 0, 0); + return 0; + } + } } - } - b = (struct xrdp_bitmap*)list_get_item(self->child_list, i); } - } - else if (scan_code == 28) /* enter */ - { - if (self->default_button != 0) + + if (self->focused_control != 0) { - if (self->notify != 0) - { - /* I think this should use def_proc */ - self->notify(self, self->default_button, 1, 0, 0); - return 0; - } + xrdp_bitmap_def_proc(self->focused_control, msg, param1, param2); } - } - else if (scan_code == 1) /* esc */ - { - if (self->esc_button != 0) - { - if (self->notify != 0) - { - /* I think this should use def_proc */ - self->notify(self, self->esc_button, 1, 0, 0); - return 0; - } - } - } } - if (self->focused_control != 0) + else if (self->type == WND_TYPE_EDIT) { - xrdp_bitmap_def_proc(self->focused_control, msg, param1, param2); + if (msg == WM_KEYDOWN) + { + scan_code = param1 % 128; + ext = param2 & 0x0100; + + /* left or up arrow */ + if ((scan_code == 75 || scan_code == 72) && + (ext || self->wm->num_lock == 0)) + { + if (self->edit_pos > 0) + { + self->edit_pos--; + xrdp_bitmap_invalidate(self, 0); + } + } + /* right or down arrow */ + else if ((scan_code == 77 || scan_code == 80) && + (ext || self->wm->num_lock == 0)) + { + if (self->edit_pos < g_mbstowcs(0, self->caption1, 0)) + { + self->edit_pos++; + xrdp_bitmap_invalidate(self, 0); + } + } + /* backspace */ + else if (scan_code == 14) + { + n = g_mbstowcs(0, self->caption1, 0); + + if (n > 0) + { + if (self->edit_pos > 0) + { + self->edit_pos--; + remove_char_at(self->caption1, 255, self->edit_pos); + xrdp_bitmap_invalidate(self, 0); + } + } + } + /* delete */ + else if (scan_code == 83 && + (ext || self->wm->num_lock == 0)) + { + n = g_mbstowcs(0, self->caption1, 0); + + if (n > 0) + { + if (self->edit_pos < n) + { + remove_char_at(self->caption1, 255, self->edit_pos); + xrdp_bitmap_invalidate(self, 0); + } + } + } + /* end */ + else if (scan_code == 79 && + (ext || self->wm->num_lock == 0)) + { + n = g_mbstowcs(0, self->caption1, 0); + + if (self->edit_pos < n) + { + self->edit_pos = n; + xrdp_bitmap_invalidate(self, 0); + } + } + /* home */ + else if ((scan_code == 71) && + (ext || (self->wm->num_lock == 0))) + { + if (self->edit_pos > 0) + { + self->edit_pos = 0; + xrdp_bitmap_invalidate(self, 0); + } + } + else + { + c = get_char_from_scan_code + (param2, scan_code, self->wm->keys, self->wm->caps_lock, + self->wm->num_lock, self->wm->scroll_lock, + &(self->wm->keymap)); + num_chars = g_mbstowcs(0, self->caption1, 0); + num_bytes = g_strlen(self->caption1); + + if ((c >= 32) && (num_chars < 127) && (num_bytes < 250)) + { + add_char_at(self->caption1, 255, c, self->edit_pos); + self->edit_pos++; + xrdp_bitmap_invalidate(self, 0); + } + } + } } - } - else if (self->type == WND_TYPE_EDIT) - { - if (msg == WM_KEYDOWN) + else if (self->type == WND_TYPE_COMBO) { - scan_code = param1 % 128; - ext = param2 & 0x0100; - /* left or up arrow */ - if ((scan_code == 75 || scan_code == 72) && - (ext || self->wm->num_lock == 0)) - { - if (self->edit_pos > 0) + if (msg == WM_KEYDOWN) { - self->edit_pos--; - xrdp_bitmap_invalidate(self, 0); + scan_code = param1 % 128; + ext = param2 & 0x0100; + + /* left or up arrow */ + if (((scan_code == 75) || (scan_code == 72)) && + (ext || (self->wm->num_lock == 0))) + { + if (self->item_index > 0) + { + self->item_index--; + xrdp_bitmap_invalidate(self, 0); + + if (self->parent->notify != 0) + { + self->parent->notify(self->parent, self, CB_ITEMCHANGE, 0, 0); + } + } + } + /* right or down arrow */ + else if ((scan_code == 77 || scan_code == 80) && + (ext || self->wm->num_lock == 0)) + { + if ((self->item_index + 1) < self->string_list->count) + { + self->item_index++; + xrdp_bitmap_invalidate(self, 0); + + if (self->parent->notify != 0) + { + self->parent->notify(self->parent, self, CB_ITEMCHANGE, 0, 0); + } + } + } } - } - /* right or down arrow */ - else if ((scan_code == 77 || scan_code == 80) && - (ext || self->wm->num_lock == 0)) - { - if (self->edit_pos < g_mbstowcs(0, self->caption1, 0)) - { - self->edit_pos++; - xrdp_bitmap_invalidate(self, 0); - } - } - /* backspace */ - else if (scan_code == 14) - { - n = g_mbstowcs(0, self->caption1, 0); - if (n > 0) - { - if (self->edit_pos > 0) - { - self->edit_pos--; - remove_char_at(self->caption1, 255, self->edit_pos); - xrdp_bitmap_invalidate(self, 0); - } - } - } - /* delete */ - else if (scan_code == 83 && - (ext || self->wm->num_lock == 0)) - { - n = g_mbstowcs(0, self->caption1, 0); - if (n > 0) - { - if (self->edit_pos < n) - { - remove_char_at(self->caption1, 255, self->edit_pos); - xrdp_bitmap_invalidate(self, 0); - } - } - } - /* end */ - else if (scan_code == 79 && - (ext || self->wm->num_lock == 0)) - { - n = g_mbstowcs(0, self->caption1, 0); - if (self->edit_pos < n) - { - self->edit_pos = n; - xrdp_bitmap_invalidate(self, 0); - } - } - /* home */ - else if ((scan_code == 71) && - (ext || (self->wm->num_lock == 0))) - { - if (self->edit_pos > 0) - { - self->edit_pos = 0; - xrdp_bitmap_invalidate(self, 0); - } - } - else - { - c = get_char_from_scan_code - (param2, scan_code, self->wm->keys, self->wm->caps_lock, - self->wm->num_lock, self->wm->scroll_lock, - &(self->wm->keymap)); - num_chars = g_mbstowcs(0, self->caption1, 0); - num_bytes = g_strlen(self->caption1); - if ((c >= 32) && (num_chars < 127) && (num_bytes < 250)) - { - add_char_at(self->caption1, 255, c, self->edit_pos); - self->edit_pos++; - xrdp_bitmap_invalidate(self, 0); - } - } } - } - else if (self->type == WND_TYPE_COMBO) - { - if (msg == WM_KEYDOWN) + else if (self->type == WND_TYPE_SPECIAL) { - scan_code = param1 % 128; - ext = param2 & 0x0100; - /* left or up arrow */ - if (((scan_code == 75) || (scan_code == 72)) && - (ext || (self->wm->num_lock == 0))) - { - if (self->item_index > 0) + if (msg == WM_MOUSEMOVE) { - self->item_index--; - xrdp_bitmap_invalidate(self, 0); - if (self->parent->notify != 0) - { - self->parent->notify(self->parent, self, CB_ITEMCHANGE, 0, 0); - } + if (self->item_height > 0 && self->popped_from != 0) + { + i = param2; + i = i / self->item_height; + + if (i != self->item_index && + i < self->popped_from->string_list->count) + { + self->item_index = i; + xrdp_bitmap_invalidate(self, 0); + } + } } - } - /* right or down arrow */ - else if ((scan_code == 77 || scan_code == 80) && - (ext || self->wm->num_lock == 0)) - { - if ((self->item_index + 1) < self->string_list->count) + else if (msg == WM_LBUTTONUP) { - self->item_index++; - xrdp_bitmap_invalidate(self, 0); - if (self->parent->notify != 0) - { - self->parent->notify(self->parent, self, CB_ITEMCHANGE, 0, 0); - } + if (self->popped_from != 0) + { + self->popped_from->item_index = self->item_index; + xrdp_bitmap_invalidate(self->popped_from, 0); + + if (self->popped_from->parent->notify != 0) + { + self->popped_from->parent->notify(self->popped_from->parent, + self->popped_from, + CB_ITEMCHANGE, 0, 0); + } + } } - } } - } - else if (self->type == WND_TYPE_SPECIAL) - { - if (msg == WM_MOUSEMOVE) - { - if (self->item_height > 0 && self->popped_from != 0) - { - i = param2; - i = i / self->item_height; - if (i != self->item_index && - i < self->popped_from->string_list->count) - { - self->item_index = i; - xrdp_bitmap_invalidate(self, 0); - } - } - } - else if (msg == WM_LBUTTONUP) - { - if (self->popped_from != 0) - { - self->popped_from->item_index = self->item_index; - xrdp_bitmap_invalidate(self->popped_from, 0); - if (self->popped_from->parent->notify != 0) - { - self->popped_from->parent->notify(self->popped_from->parent, - self->popped_from, - CB_ITEMCHANGE, 0, 0); - } - } - } - } - return 0; + + return 0; } /*****************************************************************************/ /* convert the controls coords to screen coords */ int APP_CC -xrdp_bitmap_to_screenx(struct xrdp_bitmap* self, int x) +xrdp_bitmap_to_screenx(struct xrdp_bitmap *self, int x) { - int i; + int i; - i = x; - while (self != 0) - { - i = i + self->left; - self = self->parent; - } - return i; + i = x; + + while (self != 0) + { + i = i + self->left; + self = self->parent; + } + + return i; } /*****************************************************************************/ /* convert the controls coords to screen coords */ int APP_CC -xrdp_bitmap_to_screeny(struct xrdp_bitmap* self, int y) +xrdp_bitmap_to_screeny(struct xrdp_bitmap *self, int y) { - int i; + int i; - i = y; - while (self != 0) - { - i = i + self->top; - self = self->parent; - } - return i; + i = y; + + while (self != 0) + { + i = i + self->top; + self = self->parent; + } + + return i; } /*****************************************************************************/ /* convert the screen coords to controls coords */ int APP_CC -xrdp_bitmap_from_screenx(struct xrdp_bitmap* self, int x) +xrdp_bitmap_from_screenx(struct xrdp_bitmap *self, int x) { - int i; + int i; - i = x; - while (self != 0) - { - i = i - self->left; - self = self->parent; - } - return i; + i = x; + + while (self != 0) + { + i = i - self->left; + self = self->parent; + } + + return i; } /*****************************************************************************/ /* convert the screen coords to controls coords */ int APP_CC -xrdp_bitmap_from_screeny(struct xrdp_bitmap* self, int y) +xrdp_bitmap_from_screeny(struct xrdp_bitmap *self, int y) { - int i; + int i; - i = y; - while (self != 0) - { - i = i - self->top; - self = self->parent; - } - return i; + i = y; + + while (self != 0) + { + i = i - self->top; + self = self->parent; + } + + return i; } /*****************************************************************************/ int APP_CC -xrdp_bitmap_get_screen_clip(struct xrdp_bitmap* self, - struct xrdp_painter* painter, - struct xrdp_rect* rect, - int* dx, int* dy) +xrdp_bitmap_get_screen_clip(struct xrdp_bitmap *self, + struct xrdp_painter *painter, + struct xrdp_rect *rect, + int *dx, int *dy) { - int ldx; - int ldy; + int ldx; + int ldy; - if (painter->use_clip) - { - *rect = painter->clip; - } - else - { - rect->left = 0; - rect->top = 0; - rect->right = self->width; - rect->bottom = self->height; - } - ldx = xrdp_bitmap_to_screenx(self, 0); - ldy = xrdp_bitmap_to_screeny(self, 0); - rect->left += ldx; - rect->top += ldy; - rect->right += ldx; - rect->bottom += ldy; - if (dx != 0) - { - *dx = ldx; - } - if (dy != 0) - { - *dy = ldy; - } - return 0; + if (painter->use_clip) + { + *rect = painter->clip; + } + else + { + rect->left = 0; + rect->top = 0; + rect->right = self->width; + rect->bottom = self->height; + } + + ldx = xrdp_bitmap_to_screenx(self, 0); + ldy = xrdp_bitmap_to_screeny(self, 0); + rect->left += ldx; + rect->top += ldy; + rect->right += ldx; + rect->bottom += ldy; + + if (dx != 0) + { + *dx = ldx; + } + + if (dy != 0) + { + *dy = ldy; + } + + return 0; } diff --git a/xrdp/xrdp_cache.c b/xrdp/xrdp_cache.c index 17316633..dfc7e60b 100644 --- a/xrdp/xrdp_cache.c +++ b/xrdp/xrdp_cache.c @@ -1,418 +1,451 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - cache - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * cache + */ #include "xrdp.h" /*****************************************************************************/ -struct xrdp_cache* APP_CC -xrdp_cache_create(struct xrdp_wm* owner, - struct xrdp_session* session, - struct xrdp_client_info* client_info) +struct xrdp_cache *APP_CC +xrdp_cache_create(struct xrdp_wm *owner, + struct xrdp_session *session, + struct xrdp_client_info *client_info) { - struct xrdp_cache* self; + struct xrdp_cache *self; - self = (struct xrdp_cache*)g_malloc(sizeof(struct xrdp_cache), 1); - self->wm = owner; - self->session = session; - self->use_bitmap_comp = client_info->use_bitmap_comp; - self->cache1_entries = client_info->cache1_entries; - self->cache1_size = client_info->cache1_size; - self->cache2_entries = client_info->cache2_entries; - self->cache2_size = client_info->cache2_size; - self->cache3_entries = client_info->cache3_entries; - self->cache3_size = client_info->cache3_size; - self->bitmap_cache_persist_enable = client_info->bitmap_cache_persist_enable; - self->bitmap_cache_version = client_info->bitmap_cache_version; - self->pointer_cache_entries = client_info->pointer_cache_entries; - self->xrdp_os_del_list = list_create(); - return self; + self = (struct xrdp_cache *)g_malloc(sizeof(struct xrdp_cache), 1); + self->wm = owner; + self->session = session; + self->use_bitmap_comp = client_info->use_bitmap_comp; + self->cache1_entries = client_info->cache1_entries; + self->cache1_size = client_info->cache1_size; + self->cache2_entries = client_info->cache2_entries; + self->cache2_size = client_info->cache2_size; + self->cache3_entries = client_info->cache3_entries; + self->cache3_size = client_info->cache3_size; + self->bitmap_cache_persist_enable = client_info->bitmap_cache_persist_enable; + self->bitmap_cache_version = client_info->bitmap_cache_version; + self->pointer_cache_entries = client_info->pointer_cache_entries; + self->xrdp_os_del_list = list_create(); + return self; } /*****************************************************************************/ void APP_CC -xrdp_cache_delete(struct xrdp_cache* self) +xrdp_cache_delete(struct xrdp_cache *self) { - int i; - int j; + int i; + int j; - if (self == 0) - { - return; - } - /* free all the cached bitmaps */ - for (i = 0; i < 3; i++) - { - for (j = 0; j < 2000; j++) + if (self == 0) { - xrdp_bitmap_delete(self->bitmap_items[i][j].bitmap); + return; } - } - /* free all the cached font items */ - for (i = 0; i < 12; i++) - { - for (j = 0; j < 256; j++) - { - g_free(self->char_items[i][j].font_item.data); - } - } - /* free all the off screen bitmaps */ - for (i = 0; i < 2000; i++) - { - xrdp_bitmap_delete(self->os_bitmap_items[i].bitmap); - } - list_delete(self->xrdp_os_del_list); - g_free(self); + /* free all the cached bitmaps */ + for (i = 0; i < 3; i++) + { + for (j = 0; j < 2000; j++) + { + xrdp_bitmap_delete(self->bitmap_items[i][j].bitmap); + } + } + + /* free all the cached font items */ + for (i = 0; i < 12; i++) + { + for (j = 0; j < 256; j++) + { + g_free(self->char_items[i][j].font_item.data); + } + } + + /* free all the off screen bitmaps */ + for (i = 0; i < 2000; i++) + { + xrdp_bitmap_delete(self->os_bitmap_items[i].bitmap); + } + + list_delete(self->xrdp_os_del_list); + + g_free(self); } /*****************************************************************************/ int APP_CC -xrdp_cache_reset(struct xrdp_cache* self, - struct xrdp_client_info* client_info) +xrdp_cache_reset(struct xrdp_cache *self, + struct xrdp_client_info *client_info) { - struct xrdp_wm* wm; - struct xrdp_session* session; - int i; - int j; + struct xrdp_wm *wm; + struct xrdp_session *session; + int i; + int j; - /* free all the cached bitmaps */ - for (i = 0; i < 3; i++) - { - for (j = 0; j < 2000; j++) + /* free all the cached bitmaps */ + for (i = 0; i < 3; i++) { - xrdp_bitmap_delete(self->bitmap_items[i][j].bitmap); + for (j = 0; j < 2000; j++) + { + xrdp_bitmap_delete(self->bitmap_items[i][j].bitmap); + } } - } - /* free all the cached font items */ - for (i = 0; i < 12; i++) - { - for (j = 0; j < 256; j++) + + /* free all the cached font items */ + for (i = 0; i < 12; i++) { - g_free(self->char_items[i][j].font_item.data); + for (j = 0; j < 256; j++) + { + g_free(self->char_items[i][j].font_item.data); + } } - } - /* save these */ - wm = self->wm; - session = self->session; - /* set whole struct to zero */ - g_memset(self, 0, sizeof(struct xrdp_cache)); - /* set some stuff back */ - self->wm = wm; - self->session = session; - self->use_bitmap_comp = client_info->use_bitmap_comp; - self->cache1_entries = client_info->cache1_entries; - self->cache1_size = client_info->cache1_size; - self->cache2_entries = client_info->cache2_entries; - self->cache2_size = client_info->cache2_size; - self->cache3_entries = client_info->cache3_entries; - self->cache3_size = client_info->cache3_size; - self->bitmap_cache_persist_enable = client_info->bitmap_cache_persist_enable; - self->bitmap_cache_version = client_info->bitmap_cache_version; - self->pointer_cache_entries = client_info->pointer_cache_entries; - return 0; + + /* save these */ + wm = self->wm; + session = self->session; + /* set whole struct to zero */ + g_memset(self, 0, sizeof(struct xrdp_cache)); + /* set some stuff back */ + self->wm = wm; + self->session = session; + self->use_bitmap_comp = client_info->use_bitmap_comp; + self->cache1_entries = client_info->cache1_entries; + self->cache1_size = client_info->cache1_size; + self->cache2_entries = client_info->cache2_entries; + self->cache2_size = client_info->cache2_size; + self->cache3_entries = client_info->cache3_entries; + self->cache3_size = client_info->cache3_size; + self->bitmap_cache_persist_enable = client_info->bitmap_cache_persist_enable; + self->bitmap_cache_version = client_info->bitmap_cache_version; + self->pointer_cache_entries = client_info->pointer_cache_entries; + return 0; } /*****************************************************************************/ /* returns cache id */ int APP_CC -xrdp_cache_add_bitmap(struct xrdp_cache* self, struct xrdp_bitmap* bitmap, +xrdp_cache_add_bitmap(struct xrdp_cache *self, struct xrdp_bitmap *bitmap, int hints) { - int i = 0; - int j = 0; - int oldest = 0; - int cache_id = 0; - int cache_idx = 0; - int bmp_size = 0; - int e = 0; - int Bpp = 0; + int i = 0; + int j = 0; + int oldest = 0; + int cache_id = 0; + int cache_idx = 0; + int bmp_size = 0; + int e = 0; + int Bpp = 0; - e = bitmap->width % 4; - if (e != 0) - { - e = 4 - e; - } - Bpp = (bitmap->bpp + 7) / 8; - bmp_size = (bitmap->width + e) * bitmap->height * Bpp; - self->bitmap_stamp++; - /* look for match */ - if (bmp_size <= self->cache1_size) - { - i = 0; - for (j = 0; j < self->cache1_entries; j++) + e = bitmap->width % 4; + + if (e != 0) { + e = 4 - e; + } + + Bpp = (bitmap->bpp + 7) / 8; + bmp_size = (bitmap->width + e) * bitmap->height * Bpp; + self->bitmap_stamp++; + + /* look for match */ + if (bmp_size <= self->cache1_size) + { + i = 0; + + for (j = 0; j < self->cache1_entries; j++) + { #ifdef USE_CRC - if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) + + if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) #else - if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) + if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif - { - self->bitmap_items[i][j].stamp = self->bitmap_stamp; - DEBUG(("found bitmap at %d %d", i, j)); - xrdp_bitmap_delete(bitmap); - return MAKELONG(j, i); - } + { + self->bitmap_items[i][j].stamp = self->bitmap_stamp; + DEBUG(("found bitmap at %d %d", i, j)); + xrdp_bitmap_delete(bitmap); + return MAKELONG(j, i); + } + } } - } - else if (bmp_size <= self->cache2_size) - { - i = 1; - for (j = 0; j < self->cache2_entries; j++) + else if (bmp_size <= self->cache2_size) { + i = 1; + + for (j = 0; j < self->cache2_entries; j++) + { #ifdef USE_CRC - if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) + + if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) #else - if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) + if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif - { - self->bitmap_items[i][j].stamp = self->bitmap_stamp; - DEBUG(("found bitmap at %d %d", i, j)); - xrdp_bitmap_delete(bitmap); - return MAKELONG(j, i); - } + { + self->bitmap_items[i][j].stamp = self->bitmap_stamp; + DEBUG(("found bitmap at %d %d", i, j)); + xrdp_bitmap_delete(bitmap); + return MAKELONG(j, i); + } + } } - } - else if (bmp_size <= self->cache3_size) - { - i = 2; - for (j = 0; j < self->cache3_entries; j++) + else if (bmp_size <= self->cache3_size) { + i = 2; + + for (j = 0; j < self->cache3_entries; j++) + { #ifdef USE_CRC - if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) + + if (xrdp_bitmap_compare_with_crc(self->bitmap_items[i][j].bitmap, bitmap)) #else - if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) + if (xrdp_bitmap_compare(self->bitmap_items[i][j].bitmap, bitmap)) #endif - { - self->bitmap_items[i][j].stamp = self->bitmap_stamp; - DEBUG(("found bitmap at %d %d", i, j)); - xrdp_bitmap_delete(bitmap); - return MAKELONG(j, i); - } + { + self->bitmap_items[i][j].stamp = self->bitmap_stamp; + DEBUG(("found bitmap at %d %d", i, j)); + xrdp_bitmap_delete(bitmap); + return MAKELONG(j, i); + } + } } - } - else - { - g_writeln("error in xrdp_cache_add_bitmap, too big(%d)", bmp_size); - } - /* look for oldest */ - cache_id = 0; - cache_idx = 0; - oldest = 0x7fffffff; - if (bmp_size <= self->cache1_size) - { - i = 0; - for (j = 0; j < self->cache1_entries; j++) + else { - if (self->bitmap_items[i][j].stamp < oldest) - { - oldest = self->bitmap_items[i][j].stamp; - cache_id = i; - cache_idx = j; - } + g_writeln("error in xrdp_cache_add_bitmap, too big(%d)", bmp_size); } - } - else if (bmp_size <= self->cache2_size) - { - i = 1; - for (j = 0; j < self->cache2_entries; j++) + + /* look for oldest */ + cache_id = 0; + cache_idx = 0; + oldest = 0x7fffffff; + + if (bmp_size <= self->cache1_size) { - if (self->bitmap_items[i][j].stamp < oldest) - { - oldest = self->bitmap_items[i][j].stamp; - cache_id = i; - cache_idx = j; - } + i = 0; + + for (j = 0; j < self->cache1_entries; j++) + { + if (self->bitmap_items[i][j].stamp < oldest) + { + oldest = self->bitmap_items[i][j].stamp; + cache_id = i; + cache_idx = j; + } + } } - } - else if (bmp_size <= self->cache3_size) - { - i = 2; - for (j = 0; j < self->cache3_entries; j++) + else if (bmp_size <= self->cache2_size) { - if (self->bitmap_items[i][j].stamp < oldest) - { - oldest = self->bitmap_items[i][j].stamp; - cache_id = i; - cache_idx = j; - } + i = 1; + + for (j = 0; j < self->cache2_entries; j++) + { + if (self->bitmap_items[i][j].stamp < oldest) + { + oldest = self->bitmap_items[i][j].stamp; + cache_id = i; + cache_idx = j; + } + } } - } - DEBUG(("adding bitmap at %d %d", cache_id, cache_idx)); - /* set, send bitmap and return */ - xrdp_bitmap_delete(self->bitmap_items[cache_id][cache_idx].bitmap); - self->bitmap_items[cache_id][cache_idx].bitmap = bitmap; - self->bitmap_items[cache_id][cache_idx].stamp = self->bitmap_stamp; - if (self->use_bitmap_comp) - { - if (self->bitmap_cache_version & 4) + else if (bmp_size <= self->cache3_size) { - if (libxrdp_orders_send_bitmap3(self->session, bitmap->width, - bitmap->height, bitmap->bpp, - bitmap->data, cache_id, cache_idx, - hints) == 0) - { - return MAKELONG(cache_idx, cache_id); - } + i = 2; + + for (j = 0; j < self->cache3_entries; j++) + { + if (self->bitmap_items[i][j].stamp < oldest) + { + oldest = self->bitmap_items[i][j].stamp; + cache_id = i; + cache_idx = j; + } + } } - if (self->bitmap_cache_version & 2) + + DEBUG(("adding bitmap at %d %d", cache_id, cache_idx)); + /* set, send bitmap and return */ + xrdp_bitmap_delete(self->bitmap_items[cache_id][cache_idx].bitmap); + self->bitmap_items[cache_id][cache_idx].bitmap = bitmap; + self->bitmap_items[cache_id][cache_idx].stamp = self->bitmap_stamp; + + if (self->use_bitmap_comp) { - libxrdp_orders_send_bitmap2(self->session, bitmap->width, - bitmap->height, bitmap->bpp, - bitmap->data, cache_id, cache_idx, - hints); + if (self->bitmap_cache_version & 4) + { + if (libxrdp_orders_send_bitmap3(self->session, bitmap->width, + bitmap->height, bitmap->bpp, + bitmap->data, cache_id, cache_idx, + hints) == 0) + { + return MAKELONG(cache_idx, cache_id); + } + } + + if (self->bitmap_cache_version & 2) + { + libxrdp_orders_send_bitmap2(self->session, bitmap->width, + bitmap->height, bitmap->bpp, + bitmap->data, cache_id, cache_idx, + hints); + } + else if (self->bitmap_cache_version & 1) + { + libxrdp_orders_send_bitmap(self->session, bitmap->width, + bitmap->height, bitmap->bpp, + bitmap->data, cache_id, cache_idx); + } } - else if (self->bitmap_cache_version & 1) + else { - libxrdp_orders_send_bitmap(self->session, bitmap->width, - bitmap->height, bitmap->bpp, - bitmap->data, cache_id, cache_idx); + if (self->bitmap_cache_version & 2) + { + libxrdp_orders_send_raw_bitmap2(self->session, bitmap->width, + bitmap->height, bitmap->bpp, + bitmap->data, cache_id, cache_idx); + } + else if (self->bitmap_cache_version & 1) + { + libxrdp_orders_send_raw_bitmap(self->session, bitmap->width, + bitmap->height, bitmap->bpp, + bitmap->data, cache_id, cache_idx); + } } - } - else - { - if (self->bitmap_cache_version & 2) - { - libxrdp_orders_send_raw_bitmap2(self->session, bitmap->width, - bitmap->height, bitmap->bpp, - bitmap->data, cache_id, cache_idx); - } - else if (self->bitmap_cache_version & 1) - { - libxrdp_orders_send_raw_bitmap(self->session, bitmap->width, - bitmap->height, bitmap->bpp, - bitmap->data, cache_id, cache_idx); - } - } - return MAKELONG(cache_idx, cache_id); + + return MAKELONG(cache_idx, cache_id); } /*****************************************************************************/ /* not used */ /* not sure how to use a palette in rdp */ int APP_CC -xrdp_cache_add_palette(struct xrdp_cache* self, int* palette) +xrdp_cache_add_palette(struct xrdp_cache *self, int *palette) { - int i; - int oldest; - int index; + int i; + int oldest; + int index; - if (self == 0) - { - return 0; - } - if (palette == 0) - { - return 0; - } - if (self->wm->screen->bpp > 8) - { - return 0; - } - self->palette_stamp++; - /* look for match */ - for (i = 0; i < 6; i++) - { - if (g_memcmp(palette, self->palette_items[i].palette, - 256 * sizeof(int)) == 0) + if (self == 0) { - self->palette_items[i].stamp = self->palette_stamp; - return i; + return 0; } - } - /* look for oldest */ - index = 0; - oldest = 0x7fffffff; - for (i = 0; i < 6; i++) - { - if (self->palette_items[i].stamp < oldest) + + if (palette == 0) { - oldest = self->palette_items[i].stamp; - index = i; + return 0; } - } - /* set, send palette and return */ - g_memcpy(self->palette_items[index].palette, palette, 256 * sizeof(int)); - self->palette_items[index].stamp = self->palette_stamp; - libxrdp_orders_send_palette(self->session, palette, index); - return index; + + if (self->wm->screen->bpp > 8) + { + return 0; + } + + self->palette_stamp++; + + /* look for match */ + for (i = 0; i < 6; i++) + { + if (g_memcmp(palette, self->palette_items[i].palette, + 256 * sizeof(int)) == 0) + { + self->palette_items[i].stamp = self->palette_stamp; + return i; + } + } + + /* look for oldest */ + index = 0; + oldest = 0x7fffffff; + + for (i = 0; i < 6; i++) + { + if (self->palette_items[i].stamp < oldest) + { + oldest = self->palette_items[i].stamp; + index = i; + } + } + + /* set, send palette and return */ + g_memcpy(self->palette_items[index].palette, palette, 256 * sizeof(int)); + self->palette_items[index].stamp = self->palette_stamp; + libxrdp_orders_send_palette(self->session, palette, index); + return index; } /*****************************************************************************/ int APP_CC -xrdp_cache_add_char(struct xrdp_cache* self, - struct xrdp_font_char* font_item) +xrdp_cache_add_char(struct xrdp_cache *self, + struct xrdp_font_char *font_item) { - int i; - int j; - int oldest; - int f; - int c; - int datasize; - struct xrdp_font_char* fi; + int i; + int j; + int oldest; + int f; + int c; + int datasize; + struct xrdp_font_char *fi; - self->char_stamp++; - /* look for match */ - for (i = 7; i < 12; i++) - { - for (j = 0; j < 250; j++) + self->char_stamp++; + + /* look for match */ + for (i = 7; i < 12; i++) { - if (xrdp_font_item_compare(&self->char_items[i][j].font_item, font_item)) - { - self->char_items[i][j].stamp = self->char_stamp; - DEBUG(("found font at %d %d", i, j)); - return MAKELONG(j, i); - } + for (j = 0; j < 250; j++) + { + if (xrdp_font_item_compare(&self->char_items[i][j].font_item, font_item)) + { + self->char_items[i][j].stamp = self->char_stamp; + DEBUG(("found font at %d %d", i, j)); + return MAKELONG(j, i); + } + } } - } - /* look for oldest */ - f = 0; - c = 0; - oldest = 0x7fffffff; - for (i = 7; i < 12; i++) - { - for (j = 0; j < 250; j++) + + /* look for oldest */ + f = 0; + c = 0; + oldest = 0x7fffffff; + + for (i = 7; i < 12; i++) { - if (self->char_items[i][j].stamp < oldest) - { - oldest = self->char_items[i][j].stamp; - f = i; - c = j; - } + for (j = 0; j < 250; j++) + { + if (self->char_items[i][j].stamp < oldest) + { + oldest = self->char_items[i][j].stamp; + f = i; + c = j; + } + } } - } - DEBUG(("adding char at %d %d", f, c)); - /* set, send char and return */ - fi = &self->char_items[f][c].font_item; - g_free(fi->data); - datasize = FONT_DATASIZE(font_item); - fi->data = (char*)g_malloc(datasize, 1); - g_memcpy(fi->data, font_item->data, datasize); - fi->offset = font_item->offset; - fi->baseline = font_item->baseline; - fi->width = font_item->width; - fi->height = font_item->height; - self->char_items[f][c].stamp = self->char_stamp; - libxrdp_orders_send_font(self->session, fi, f, c); - return MAKELONG(c, f); + + DEBUG(("adding char at %d %d", f, c)); + /* set, send char and return */ + fi = &self->char_items[f][c].font_item; + g_free(fi->data); + datasize = FONT_DATASIZE(font_item); + fi->data = (char *)g_malloc(datasize, 1); + g_memcpy(fi->data, font_item->data, datasize); + fi->offset = font_item->offset; + fi->baseline = font_item->baseline; + fi->width = font_item->width; + fi->height = font_item->height; + self->char_items[f][c].stamp = self->char_stamp; + libxrdp_orders_send_font(self->session, fi, f, c); + return MAKELONG(c, f); } /*****************************************************************************/ @@ -421,191 +454,208 @@ xrdp_cache_add_char(struct xrdp_cache* self, returns the index in the cache does not take ownership of pointer_item */ int APP_CC -xrdp_cache_add_pointer(struct xrdp_cache* self, - struct xrdp_pointer_item* pointer_item) +xrdp_cache_add_pointer(struct xrdp_cache *self, + struct xrdp_pointer_item *pointer_item) { - int i; - int oldest; - int index; + int i; + int oldest; + int index; - if (self == 0) - { - return 0; - } - self->pointer_stamp++; - /* look for match */ - for (i = 2; i < self->pointer_cache_entries; i++) - { - if (self->pointer_items[i].x == pointer_item->x && - self->pointer_items[i].y == pointer_item->y && - g_memcmp(self->pointer_items[i].data, - pointer_item->data, 32 * 32 * 3) == 0 && - g_memcmp(self->pointer_items[i].mask, - pointer_item->mask, 32 * 32 / 8) == 0) + if (self == 0) { - self->pointer_items[i].stamp = self->pointer_stamp; - xrdp_wm_set_pointer(self->wm, i); - self->wm->current_pointer = i; - DEBUG(("found pointer at %d", i)); - return i; + return 0; } - } - /* look for oldest */ - index = 2; - oldest = 0x7fffffff; - for (i = 2; i < self->pointer_cache_entries; i++) - { - if (self->pointer_items[i].stamp < oldest) + + self->pointer_stamp++; + + /* look for match */ + for (i = 2; i < self->pointer_cache_entries; i++) { - oldest = self->pointer_items[i].stamp; - index = i; + if (self->pointer_items[i].x == pointer_item->x && + self->pointer_items[i].y == pointer_item->y && + g_memcmp(self->pointer_items[i].data, + pointer_item->data, 32 * 32 * 3) == 0 && + g_memcmp(self->pointer_items[i].mask, + pointer_item->mask, 32 * 32 / 8) == 0) + { + self->pointer_items[i].stamp = self->pointer_stamp; + xrdp_wm_set_pointer(self->wm, i); + self->wm->current_pointer = i; + DEBUG(("found pointer at %d", i)); + return i; + } } - } - self->pointer_items[index].x = pointer_item->x; - self->pointer_items[index].y = pointer_item->y; - g_memcpy(self->pointer_items[index].data, - pointer_item->data, 32 * 32 * 3); - g_memcpy(self->pointer_items[index].mask, - pointer_item->mask, 32 * 32 / 8); - self->pointer_items[index].stamp = self->pointer_stamp; - xrdp_wm_send_pointer(self->wm, index, - self->pointer_items[index].data, - self->pointer_items[index].mask, - self->pointer_items[index].x, - self->pointer_items[index].y); - self->wm->current_pointer = index; - DEBUG(("adding pointer at %d", index)); - return index; + + /* look for oldest */ + index = 2; + oldest = 0x7fffffff; + + for (i = 2; i < self->pointer_cache_entries; i++) + { + if (self->pointer_items[i].stamp < oldest) + { + oldest = self->pointer_items[i].stamp; + index = i; + } + } + + self->pointer_items[index].x = pointer_item->x; + self->pointer_items[index].y = pointer_item->y; + g_memcpy(self->pointer_items[index].data, + pointer_item->data, 32 * 32 * 3); + g_memcpy(self->pointer_items[index].mask, + pointer_item->mask, 32 * 32 / 8); + self->pointer_items[index].stamp = self->pointer_stamp; + xrdp_wm_send_pointer(self->wm, index, + self->pointer_items[index].data, + self->pointer_items[index].mask, + self->pointer_items[index].x, + self->pointer_items[index].y); + self->wm->current_pointer = index; + DEBUG(("adding pointer at %d", index)); + return index; } /*****************************************************************************/ /* this does not take owership of pointer_item, it makes a copy */ int APP_CC -xrdp_cache_add_pointer_static(struct xrdp_cache* self, - struct xrdp_pointer_item* pointer_item, +xrdp_cache_add_pointer_static(struct xrdp_cache *self, + struct xrdp_pointer_item *pointer_item, int index) { - if (self == 0) - { - return 0; - } - self->pointer_items[index].x = pointer_item->x; - self->pointer_items[index].y = pointer_item->y; - g_memcpy(self->pointer_items[index].data, - pointer_item->data, 32 * 32 * 3); - g_memcpy(self->pointer_items[index].mask, - pointer_item->mask, 32 * 32 / 8); - self->pointer_items[index].stamp = self->pointer_stamp; - xrdp_wm_send_pointer(self->wm, index, - self->pointer_items[index].data, - self->pointer_items[index].mask, - self->pointer_items[index].x, - self->pointer_items[index].y); - self->wm->current_pointer = index; - DEBUG(("adding pointer at %d", index)); - return index; + if (self == 0) + { + return 0; + } + + self->pointer_items[index].x = pointer_item->x; + self->pointer_items[index].y = pointer_item->y; + g_memcpy(self->pointer_items[index].data, + pointer_item->data, 32 * 32 * 3); + g_memcpy(self->pointer_items[index].mask, + pointer_item->mask, 32 * 32 / 8); + self->pointer_items[index].stamp = self->pointer_stamp; + xrdp_wm_send_pointer(self->wm, index, + self->pointer_items[index].data, + self->pointer_items[index].mask, + self->pointer_items[index].x, + self->pointer_items[index].y); + self->wm->current_pointer = index; + DEBUG(("adding pointer at %d", index)); + return index; } /*****************************************************************************/ /* this does not take owership of brush_item_data, it makes a copy */ int APP_CC -xrdp_cache_add_brush(struct xrdp_cache* self, - char* brush_item_data) +xrdp_cache_add_brush(struct xrdp_cache *self, + char *brush_item_data) { - int i; - int oldest; - int index; + int i; + int oldest; + int index; - if (self == 0) - { - return 0; - } - self->brush_stamp++; - /* look for match */ - for (i = 0; i < 64; i++) - { - if (g_memcmp(self->brush_items[i].pattern, - brush_item_data, 8) == 0) + if (self == 0) { - self->brush_items[i].stamp = self->brush_stamp; - DEBUG(("found brush at %d", i)); - return i; + return 0; } - } - /* look for oldest */ - index = 0; - oldest = 0x7fffffff; - for (i = 0; i < 64; i++) - { - if (self->brush_items[i].stamp < oldest) + + self->brush_stamp++; + + /* look for match */ + for (i = 0; i < 64; i++) { - oldest = self->brush_items[i].stamp; - index = i; + if (g_memcmp(self->brush_items[i].pattern, + brush_item_data, 8) == 0) + { + self->brush_items[i].stamp = self->brush_stamp; + DEBUG(("found brush at %d", i)); + return i; + } } - } - g_memcpy(self->brush_items[index].pattern, - brush_item_data, 8); - self->brush_items[index].stamp = self->brush_stamp; - libxrdp_orders_send_brush(self->session, 8, 8, 1, 0x81, 8, - self->brush_items[index].pattern, index); - DEBUG(("adding brush at %d", index)); - return index; + + /* look for oldest */ + index = 0; + oldest = 0x7fffffff; + + for (i = 0; i < 64; i++) + { + if (self->brush_items[i].stamp < oldest) + { + oldest = self->brush_items[i].stamp; + index = i; + } + } + + g_memcpy(self->brush_items[index].pattern, + brush_item_data, 8); + self->brush_items[index].stamp = self->brush_stamp; + libxrdp_orders_send_brush(self->session, 8, 8, 1, 0x81, 8, + self->brush_items[index].pattern, index); + DEBUG(("adding brush at %d", index)); + return index; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_cache_add_os_bitmap(struct xrdp_cache* self, struct xrdp_bitmap* bitmap, +xrdp_cache_add_os_bitmap(struct xrdp_cache *self, struct xrdp_bitmap *bitmap, int rdpindex) { - struct xrdp_os_bitmap_item* bi; + struct xrdp_os_bitmap_item *bi; - if ((rdpindex < 0) || (rdpindex >= 2000)) - { - return 1; - } - bi = self->os_bitmap_items + rdpindex; - bi->bitmap = bitmap; - return 0; + if ((rdpindex < 0) || (rdpindex >= 2000)) + { + return 1; + } + + bi = self->os_bitmap_items + rdpindex; + bi->bitmap = bitmap; + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_cache_remove_os_bitmap(struct xrdp_cache* self, int rdpindex) +xrdp_cache_remove_os_bitmap(struct xrdp_cache *self, int rdpindex) { - struct xrdp_os_bitmap_item* bi; - int index; + struct xrdp_os_bitmap_item *bi; + int index; - if ((rdpindex < 0) || (rdpindex >= 2000)) - { - return 1; - } - bi = self->os_bitmap_items + rdpindex; - if (bi->bitmap->tab_stop) - { - index = list_index_of(self->xrdp_os_del_list, rdpindex); - if (index == -1) + if ((rdpindex < 0) || (rdpindex >= 2000)) { - list_add_item(self->xrdp_os_del_list, rdpindex); + return 1; } - } - xrdp_bitmap_delete(bi->bitmap); - g_memset(bi, 0, sizeof(struct xrdp_os_bitmap_item)); - return 0; + + bi = self->os_bitmap_items + rdpindex; + + if (bi->bitmap->tab_stop) + { + index = list_index_of(self->xrdp_os_del_list, rdpindex); + + if (index == -1) + { + list_add_item(self->xrdp_os_del_list, rdpindex); + } + } + + xrdp_bitmap_delete(bi->bitmap); + g_memset(bi, 0, sizeof(struct xrdp_os_bitmap_item)); + return 0; } /*****************************************************************************/ -struct xrdp_os_bitmap_item* APP_CC -xrdp_cache_get_os_bitmap(struct xrdp_cache* self, int rdpindex) +struct xrdp_os_bitmap_item *APP_CC +xrdp_cache_get_os_bitmap(struct xrdp_cache *self, int rdpindex) { - struct xrdp_os_bitmap_item* bi; + struct xrdp_os_bitmap_item *bi; - if ((rdpindex < 0) || (rdpindex >= 2000)) - { - return 0; - } - bi = self->os_bitmap_items + rdpindex; - return bi; + if ((rdpindex < 0) || (rdpindex >= 2000)) + { + return 0; + } + + bi = self->os_bitmap_items + rdpindex; + return bi; } diff --git a/xrdp/xrdp_font.c b/xrdp/xrdp_font.c index e1c4257b..91734807 100644 --- a/xrdp/xrdp_font.c +++ b/xrdp/xrdp_font.c @@ -1,25 +1,23 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * fonts + */ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - fonts - -*/ /* The fv1 files contain Font File Header (just one) @@ -43,176 +41,197 @@ #if 0 /* not used */ static char w_char[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x08, 0x20, 0x80, - 0x08, 0x50, 0x80, - 0x04, 0x51, 0x00, - 0x04, 0x51, 0x00, - 0x04, 0x51, 0x00, - 0x02, 0x8a, 0x00, - 0x02, 0x8a, 0x00, - 0x02, 0x8a, 0x00, - 0x01, 0x04, 0x00, - 0x01, 0x04, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x20, 0x80, + 0x08, 0x50, 0x80, + 0x04, 0x51, 0x00, + 0x04, 0x51, 0x00, + 0x04, 0x51, 0x00, + 0x02, 0x8a, 0x00, + 0x02, 0x8a, 0x00, + 0x02, 0x8a, 0x00, + 0x01, 0x04, 0x00, + 0x01, 0x04, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, }; #endif /*****************************************************************************/ -struct xrdp_font* APP_CC -xrdp_font_create(struct xrdp_wm* wm) +struct xrdp_font *APP_CC +xrdp_font_create(struct xrdp_wm *wm) { - struct xrdp_font* self; - struct stream* s; - int fd; - int b; - int i; - int index; - int datasize; - int file_size; - struct xrdp_font_char* f; - char file_path[256]; + struct xrdp_font *self; + struct stream *s; + int fd; + int b; + int i; + int index; + int datasize; + int file_size; + struct xrdp_font_char *f; + char file_path[256]; - DEBUG(("in xrdp_font_create")); - g_snprintf(file_path, 255, "%s/%s", XRDP_SHARE_PATH, DEFAULT_FONT_NAME); - if (!g_file_exist(file_path)) - { - g_writeln("xrdp_font_create: error font file [%s] does not exist", - file_path); - return 0; - } - file_size = g_file_get_size(file_path); - if (file_size < 1) - { - g_writeln("xrdp_font_create: error reading font from file [%s]", - file_path); - return 0; - } - self = (struct xrdp_font*)g_malloc(sizeof(struct xrdp_font), 1); - self->wm = wm; - make_stream(s); - init_stream(s, file_size + 1024); - fd = g_file_open(file_path); - if (fd != -1) - { - b = g_file_read(fd, s->data, file_size + 1024); - g_file_close(fd); - if (b > 0) + DEBUG(("in xrdp_font_create")); + g_snprintf(file_path, 255, "%s/%s", XRDP_SHARE_PATH, DEFAULT_FONT_NAME); + + if (!g_file_exist(file_path)) { - s->end = s->data + b; - in_uint8s(s, 4); - in_uint8a(s, self->name, 32); - in_uint16_le(s, self->size); - in_uint16_le(s, self->style); - in_uint8s(s, 8); - index = 32; - while (s_check_rem(s, 16)) - { - f = self->font_items + index; - in_sint16_le(s, i); - f->width = i; - in_sint16_le(s, i); - f->height = i; - in_sint16_le(s, i); - f->baseline = i; - in_sint16_le(s, i); - f->offset = i; - in_sint16_le(s, i); - f->incby = i; - in_uint8s(s, 6); - datasize = FONT_DATASIZE(f); - if (datasize < 0 || datasize > 512) - { - /* shouldn't happen */ - g_writeln("error in xrdp_font_create, datasize wrong"); - g_writeln("width %d height %d datasize %d index %d", - f->width, f->height, datasize, index); - break; - } - if (s_check_rem(s, datasize)) - { - f->data = (char*)g_malloc(datasize, 0); - in_uint8a(s, f->data, datasize); - } - else - { - g_writeln("error in xrdp_font_create"); - } - index++; - } + g_writeln("xrdp_font_create: error font file [%s] does not exist", + file_path); + return 0; } - } - free_stream(s); -/* - self->font_items[0].offset = -4; - self->font_items[0].baseline = -16; - self->font_items[0].width = 24; - self->font_items[0].height = 16; - self->font_items[0].data = g_malloc(3 * 16, 0); - g_memcpy(self->font_items[0].data, w_char, 3 * 16); -*/ - DEBUG(("out xrdp_font_create")); - return self; + + file_size = g_file_get_size(file_path); + + if (file_size < 1) + { + g_writeln("xrdp_font_create: error reading font from file [%s]", + file_path); + return 0; + } + + self = (struct xrdp_font *)g_malloc(sizeof(struct xrdp_font), 1); + self->wm = wm; + make_stream(s); + init_stream(s, file_size + 1024); + fd = g_file_open(file_path); + + if (fd != -1) + { + b = g_file_read(fd, s->data, file_size + 1024); + g_file_close(fd); + + if (b > 0) + { + s->end = s->data + b; + in_uint8s(s, 4); + in_uint8a(s, self->name, 32); + in_uint16_le(s, self->size); + in_uint16_le(s, self->style); + in_uint8s(s, 8); + index = 32; + + while (s_check_rem(s, 16)) + { + f = self->font_items + index; + in_sint16_le(s, i); + f->width = i; + in_sint16_le(s, i); + f->height = i; + in_sint16_le(s, i); + f->baseline = i; + in_sint16_le(s, i); + f->offset = i; + in_sint16_le(s, i); + f->incby = i; + in_uint8s(s, 6); + datasize = FONT_DATASIZE(f); + + if (datasize < 0 || datasize > 512) + { + /* shouldn't happen */ + g_writeln("error in xrdp_font_create, datasize wrong"); + g_writeln("width %d height %d datasize %d index %d", + f->width, f->height, datasize, index); + break; + } + + if (s_check_rem(s, datasize)) + { + f->data = (char *)g_malloc(datasize, 0); + in_uint8a(s, f->data, datasize); + } + else + { + g_writeln("error in xrdp_font_create"); + } + + index++; + } + } + } + + free_stream(s); + /* + self->font_items[0].offset = -4; + self->font_items[0].baseline = -16; + self->font_items[0].width = 24; + self->font_items[0].height = 16; + self->font_items[0].data = g_malloc(3 * 16, 0); + g_memcpy(self->font_items[0].data, w_char, 3 * 16); + */ + DEBUG(("out xrdp_font_create")); + return self; } /*****************************************************************************/ /* free the font and all the items */ void APP_CC -xrdp_font_delete(struct xrdp_font* self) +xrdp_font_delete(struct xrdp_font *self) { - int i; + int i; - if (self == 0) - { - return; - } - for (i = 0; i < NUM_FONTS; i++) - { - g_free(self->font_items[i].data); - } - g_free(self); + if (self == 0) + { + return; + } + + for (i = 0; i < NUM_FONTS; i++) + { + g_free(self->font_items[i].data); + } + + g_free(self); } /*****************************************************************************/ /* compare the two font items returns 1 if they match */ int APP_CC -xrdp_font_item_compare(struct xrdp_font_char* font1, - struct xrdp_font_char* font2) +xrdp_font_item_compare(struct xrdp_font_char *font1, + struct xrdp_font_char *font2) { - int datasize; + int datasize; + + if (font1 == 0) + { + return 0; + } + + if (font2 == 0) + { + return 0; + } + + if (font1->offset != font2->offset) + { + return 0; + } + + if (font1->baseline != font2->baseline) + { + return 0; + } + + if (font1->width != font2->width) + { + return 0; + } + + if (font1->height != font2->height) + { + return 0; + } + + datasize = FONT_DATASIZE(font1); + + if (g_memcmp(font1->data, font2->data, datasize) == 0) + { + return 1; + } - if (font1 == 0) - { return 0; - } - if (font2 == 0) - { - return 0; - } - if (font1->offset != font2->offset) - { - return 0; - } - if (font1->baseline != font2->baseline) - { - return 0; - } - if (font1->width != font2->width) - { - return 0; - } - if (font1->height != font2->height) - { - return 0; - } - datasize = FONT_DATASIZE(font1); - if (g_memcmp(font1->data, font2->data, datasize) == 0) - { - return 1; - } - return 0; } diff --git a/xrdp/xrdp_listen.c b/xrdp/xrdp_listen.c index 82bade84..5de6f51a 100644 --- a/xrdp/xrdp_listen.c +++ b/xrdp/xrdp_listen.c @@ -1,429 +1,476 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - listen for incoming connection - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * listen for incoming connection + */ #include "xrdp.h" /* 'g_process' is protected by the semaphore 'g_process_sem'. One thread sets g_process and waits for the other to process it */ static tbus g_process_sem = 0; -static struct xrdp_process* g_process = 0; +static struct xrdp_process *g_process = 0; /*****************************************************************************/ static int -xrdp_listen_create_pro_done(struct xrdp_listen* self) +xrdp_listen_create_pro_done(struct xrdp_listen *self) { - int pid; - char text[256]; + int pid; + char text[256]; - pid = g_getpid(); - g_snprintf(text, 255, "xrdp_%8.8x_listen_pro_done_event", pid); - self->pro_done_event = g_create_wait_obj(text); - if(self->pro_done_event == 0) - { - g_writeln("Failure creating pro_done_event"); - } - return 0; + pid = g_getpid(); + g_snprintf(text, 255, "xrdp_%8.8x_listen_pro_done_event", pid); + self->pro_done_event = g_create_wait_obj(text); + + if (self->pro_done_event == 0) + { + g_writeln("Failure creating pro_done_event"); + } + + return 0; } /*****************************************************************************/ -struct xrdp_listen* APP_CC +struct xrdp_listen *APP_CC xrdp_listen_create(void) { - struct xrdp_listen* self; + struct xrdp_listen *self; - self = (struct xrdp_listen*)g_malloc(sizeof(struct xrdp_listen), 1); - xrdp_listen_create_pro_done(self); - self->process_list = list_create(); - if (g_process_sem == 0) - { - g_process_sem = tc_sem_create(0); - } - self->listen_trans = trans_create(TRANS_MODE_TCP, 16, 16); - if (self->listen_trans == 0) - { - g_writeln("xrdp_listen_create: trans_create failed"); - } - return self; + self = (struct xrdp_listen *)g_malloc(sizeof(struct xrdp_listen), 1); + xrdp_listen_create_pro_done(self); + self->process_list = list_create(); + + if (g_process_sem == 0) + { + g_process_sem = tc_sem_create(0); + } + + self->listen_trans = trans_create(TRANS_MODE_TCP, 16, 16); + + if (self->listen_trans == 0) + { + g_writeln("xrdp_listen_create: trans_create failed"); + } + + return self; } /*****************************************************************************/ void APP_CC -xrdp_listen_delete(struct xrdp_listen* self) +xrdp_listen_delete(struct xrdp_listen *self) { - if (self->listen_trans != 0) - { - trans_delete(self->listen_trans); - } - if (g_process_sem != 0) - { - tc_sem_delete(g_process_sem); - g_process_sem = 0; - } - g_delete_wait_obj(self->pro_done_event); - list_delete(self->process_list); - g_free(self); + if (self->listen_trans != 0) + { + trans_delete(self->listen_trans); + } + + if (g_process_sem != 0) + { + tc_sem_delete(g_process_sem); + g_process_sem = 0; + } + + g_delete_wait_obj(self->pro_done_event); + list_delete(self->process_list); + g_free(self); } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_listen_add_pro(struct xrdp_listen* self, struct xrdp_process* process) +xrdp_listen_add_pro(struct xrdp_listen *self, struct xrdp_process *process) { - list_add_item(self->process_list, (tbus)process); - return 0; + list_add_item(self->process_list, (tbus)process); + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_listen_delete_done_pro(struct xrdp_listen* self) +xrdp_listen_delete_done_pro(struct xrdp_listen *self) { - int i; - struct xrdp_process* pro; + int i; + struct xrdp_process *pro; - for (i = self->process_list->count - 1; i >= 0; i--) - { - pro = (struct xrdp_process*)list_get_item(self->process_list, i); - if (pro != 0) + for (i = self->process_list->count - 1; i >= 0; i--) { - if (pro->status < 0) - { - xrdp_process_delete(pro); - list_remove_item(self->process_list, i); - } + pro = (struct xrdp_process *)list_get_item(self->process_list, i); + + if (pro != 0) + { + if (pro->status < 0) + { + xrdp_process_delete(pro); + list_remove_item(self->process_list, i); + } + } } - } - return 0; + + return 0; } /*****************************************************************************/ /* i can't get stupid in_val to work, hum using global var for now */ THREAD_RV THREAD_CC -xrdp_process_run(void* in_val) +xrdp_process_run(void *in_val) { - struct xrdp_process* process; + struct xrdp_process *process; - DEBUG(("process started")); - process = g_process; - g_process = 0; - tc_sem_inc(g_process_sem); - xrdp_process_main_loop(process); - DEBUG(("process done")); - return 0; + DEBUG(("process started")); + process = g_process; + g_process = 0; + tc_sem_inc(g_process_sem); + xrdp_process_main_loop(process); + DEBUG(("process done")); + return 0; } /*****************************************************************************/ static int -xrdp_listen_get_port_address(char* port, int port_bytes, - char* address, int address_bytes, +xrdp_listen_get_port_address(char *port, int port_bytes, + char *address, int address_bytes, int *tcp_nodelay, int *tcp_keepalive, - struct xrdp_startup_params* startup_param) + struct xrdp_startup_params *startup_param) { - int fd; - int error; - int index; - char* val; - struct list* names; - struct list* values; - char cfg_file[256]; + int fd; + int error; + int index; + char *val; + struct list *names; + struct list *values; + char cfg_file[256]; - /* default to port 3389 */ - g_strncpy(port, "3389", port_bytes - 1); - /* Default to all */ - g_strncpy(address, "0.0.0.0", address_bytes - 1); - /* see if port or address is in xrdp.ini file */ - g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); - fd = g_file_open(cfg_file); - *tcp_nodelay = 0 ; - *tcp_keepalive = 0 ; - if (fd > 0) - { - names = list_create(); - names->auto_free = 1; - values = list_create(); - values->auto_free = 1; - if (file_read_section(fd, "globals", names, values) == 0) + /* default to port 3389 */ + g_strncpy(port, "3389", port_bytes - 1); + /* Default to all */ + g_strncpy(address, "0.0.0.0", address_bytes - 1); + /* see if port or address is in xrdp.ini file */ + g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + fd = g_file_open(cfg_file); + *tcp_nodelay = 0 ; + *tcp_keepalive = 0 ; + + if (fd > 0) { - for (index = 0; index < names->count; index++) - { - val = (char*)list_get_item(names, index); - if (val != 0) + names = list_create(); + names->auto_free = 1; + values = list_create(); + values->auto_free = 1; + + if (file_read_section(fd, "globals", names, values) == 0) { - if (g_strcasecmp(val, "port") == 0) - { - val = (char*)list_get_item(values, index); - error = g_atoi(val); - if ((error > 0) && (error < 65000)) + for (index = 0; index < names->count; index++) { - g_strncpy(port, val, port_bytes - 1); + val = (char *)list_get_item(names, index); + + if (val != 0) + { + if (g_strcasecmp(val, "port") == 0) + { + val = (char *)list_get_item(values, index); + error = g_atoi(val); + + if ((error > 0) && (error < 65000)) + { + g_strncpy(port, val, port_bytes - 1); + } + } + + if (g_strcasecmp(val, "address") == 0) + { + val = (char *)list_get_item(values, index); + g_strncpy(address, val, address_bytes - 1); + } + + if (g_strcasecmp(val, "fork") == 0) + { + val = (char *)list_get_item(values, index); + + if ((g_strcasecmp(val, "yes") == 0) || + (g_strcasecmp(val, "on") == 0) || + (g_strcasecmp(val, "true") == 0) || + (g_atoi(val) != 0)) + { + startup_param->fork = 1; + } + } + + if (g_strcasecmp(val, "tcp_nodelay") == 0) + { + val = (char *)list_get_item(values, index); + + if ((g_strcasecmp(val, "yes") == 0) || + (g_strcasecmp(val, "on") == 0) || + (g_strcasecmp(val, "true") == 0) || + (g_atoi(val) != 0)) + { + *tcp_nodelay = 1 ; + } + } + + if (g_strcasecmp(val, "tcp_keepalive") == 0) + { + val = (char *)list_get_item(values, index); + + if ((g_strcasecmp(val, "yes") == 0) || + (g_strcasecmp(val, "on") == 0) || + (g_strcasecmp(val, "true") == 0) || + (g_atoi(val) != 0)) + { + *tcp_keepalive = 1 ; + } + } + } } - } - if (g_strcasecmp(val, "address") == 0) - { - val = (char*)list_get_item(values, index); - g_strncpy(address, val, address_bytes - 1); - } - if (g_strcasecmp(val, "fork") == 0) - { - val = (char*)list_get_item(values, index); - if ((g_strcasecmp(val, "yes") == 0) || - (g_strcasecmp(val, "on") == 0) || - (g_strcasecmp(val, "true") == 0) || - (g_atoi(val) != 0)) - { - startup_param->fork = 1; - } - } - if (g_strcasecmp(val, "tcp_nodelay") == 0) - { - val = (char*)list_get_item(values, index); - if ((g_strcasecmp(val, "yes") == 0) || - (g_strcasecmp(val, "on") == 0) || - (g_strcasecmp(val, "true") == 0) || - (g_atoi(val) != 0)) - { - *tcp_nodelay = 1 ; - } - } - if (g_strcasecmp(val, "tcp_keepalive") == 0) - { - val = (char*)list_get_item(values, index); - if ((g_strcasecmp(val, "yes") == 0) || - (g_strcasecmp(val, "on") == 0) || - (g_strcasecmp(val, "true") == 0) || - (g_atoi(val) != 0)) - { - *tcp_keepalive = 1 ; - } - } } - } + + list_delete(names); + list_delete(values); + g_file_close(fd); } - list_delete(names); - list_delete(values); - g_file_close(fd); - } - /* startup_param overrides */ - if (startup_param->port[0] != 0) - { - g_strncpy(port, startup_param->port, port_bytes - 1); - } - return 0; + + /* startup_param overrides */ + if (startup_param->port[0] != 0) + { + g_strncpy(port, startup_param->port, port_bytes - 1); + } + + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_listen_fork(struct xrdp_listen* self, struct trans* server_trans) +xrdp_listen_fork(struct xrdp_listen *self, struct trans *server_trans) { - int pid; - struct xrdp_process* process; + int pid; + struct xrdp_process *process; - pid = g_fork(); - if (pid == 0) - { - /* child */ - /* recreate some main globals */ - xrdp_child_fork(); - /* recreate the process done wait object, not used in fork mode */ - /* close, don't delete this */ - g_close_wait_obj(self->pro_done_event); - xrdp_listen_create_pro_done(self); - /* delete listener, child need not listen */ - trans_delete(self->listen_trans); - self->listen_trans = 0; - /* new connect instance */ - process = xrdp_process_create(self, 0); - process->server_trans = server_trans; - g_process = process; - xrdp_process_run(0); - xrdp_process_delete(process); - /* mark this process to exit */ - g_set_term(1); + pid = g_fork(); + + if (pid == 0) + { + /* child */ + /* recreate some main globals */ + xrdp_child_fork(); + /* recreate the process done wait object, not used in fork mode */ + /* close, don't delete this */ + g_close_wait_obj(self->pro_done_event); + xrdp_listen_create_pro_done(self); + /* delete listener, child need not listen */ + trans_delete(self->listen_trans); + self->listen_trans = 0; + /* new connect instance */ + process = xrdp_process_create(self, 0); + process->server_trans = server_trans; + g_process = process; + xrdp_process_run(0); + xrdp_process_delete(process); + /* mark this process to exit */ + g_set_term(1); + return 0; + } + + /* parent */ + trans_delete(server_trans); return 0; - } - /* parent */ - trans_delete(server_trans); - return 0; } /*****************************************************************************/ /* a new connection is coming in */ int DEFAULT_CC -xrdp_listen_conn_in(struct trans* self, struct trans* new_self) +xrdp_listen_conn_in(struct trans *self, struct trans *new_self) { - struct xrdp_process* process; - struct xrdp_listen* lis; + struct xrdp_process *process; + struct xrdp_listen *lis; - lis = (struct xrdp_listen*)(self->callback_data); - if (lis->startup_params->fork) - { - return xrdp_listen_fork(lis, new_self); - } - process = xrdp_process_create(lis, lis->pro_done_event); - if (xrdp_listen_add_pro(lis, process) == 0) - { - /* start thread */ - process->server_trans = new_self; - g_process = process; - tc_thread_create(xrdp_process_run, 0); - tc_sem_dec(g_process_sem); /* this will wait */ - } - else - { - xrdp_process_delete(process); - } - return 0; + lis = (struct xrdp_listen *)(self->callback_data); + + if (lis->startup_params->fork) + { + return xrdp_listen_fork(lis, new_self); + } + + process = xrdp_process_create(lis, lis->pro_done_event); + + if (xrdp_listen_add_pro(lis, process) == 0) + { + /* start thread */ + process->server_trans = new_self; + g_process = process; + tc_thread_create(xrdp_process_run, 0); + tc_sem_dec(g_process_sem); /* this will wait */ + } + else + { + xrdp_process_delete(process); + } + + return 0; } /*****************************************************************************/ /* wait for incoming connections */ int APP_CC -xrdp_listen_main_loop(struct xrdp_listen* self) +xrdp_listen_main_loop(struct xrdp_listen *self) { - int error; - int robjs_count; - int cont; - int timeout = 0; - char port[128]; - char address[256]; - tbus robjs[8]; - tbus term_obj; - tbus sync_obj; - tbus done_obj; - int tcp_nodelay; - int tcp_keepalive; + int error; + int robjs_count; + int cont; + int timeout = 0; + char port[128]; + char address[256]; + tbus robjs[8]; + tbus term_obj; + tbus sync_obj; + tbus done_obj; + int tcp_nodelay; + int tcp_keepalive; + + self->status = 1; + + if (xrdp_listen_get_port_address(port, sizeof(port), + address, sizeof(address), + &tcp_nodelay, &tcp_keepalive, + self->startup_params) != 0) + { + g_writeln("xrdp_listen_main_loop: xrdp_listen_get_port failed"); + self->status = -1; + return 1; + } + + /*Create socket*/ + error = trans_listen_address(self->listen_trans, port, address); + + if (error == 0) + { + if (tcp_nodelay) + { + if (g_tcp_set_no_delay(self->listen_trans->sck)) + { + g_writeln("Error setting tcp_nodelay"); + } + } + + if (tcp_keepalive) + { + if (g_tcp_set_keepalive(self->listen_trans->sck)) + { + g_writeln("Error setting tcp_keepalive"); + } + } + + self->listen_trans->trans_conn_in = xrdp_listen_conn_in; + self->listen_trans->callback_data = self; + term_obj = g_get_term_event(); /*Global termination event */ + sync_obj = g_get_sync_event(); + done_obj = self->pro_done_event; + cont = 1; + + while (cont) + { + /* build the wait obj list */ + robjs_count = 0; + robjs[robjs_count++] = term_obj; + robjs[robjs_count++] = sync_obj; + robjs[robjs_count++] = done_obj; + timeout = -1; + + if (trans_get_wait_objs(self->listen_trans, robjs, &robjs_count) != 0) + { + g_writeln("Listening socket is in wrong state we terminate listener") ; + break; + } + + /* wait - timeout -1 means wait indefinitely*/ + if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) + { + /* error, should not get here */ + g_sleep(100); + } + + if (g_is_wait_obj_set(term_obj)) /* termination called */ + { + break; + } + + if (g_is_wait_obj_set(sync_obj)) /* some function must be processed by this thread */ + { + g_reset_wait_obj(sync_obj); + g_process_waiting_function(); /* run the function */ + } + + if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ + { + g_reset_wait_obj(done_obj); + /* a process has died remove it from lists*/ + xrdp_listen_delete_done_pro(self); + } + + /* Run the callback when accept() returns a new socket*/ + if (trans_check_wait_objs(self->listen_trans) != 0) + { + break; + } + } + + /* stop listening */ + trans_delete(self->listen_trans); + self->listen_trans = 0; + /* second loop to wait for all process threads to close */ + cont = 1; + + while (cont) + { + if (self->process_list->count == 0) + { + break; + } + + timeout = -1; + /* build the wait obj list */ + robjs_count = 0; + robjs[robjs_count++] = sync_obj; + robjs[robjs_count++] = done_obj; + + /* wait - timeout -1 means wait indefinitely*/ + if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) + { + /* error, should not get here */ + g_sleep(100); + } + + if (g_is_wait_obj_set(sync_obj)) /* some function must be processed by this thread */ + { + g_reset_wait_obj(sync_obj); + g_process_waiting_function(); /* run the function that is waiting*/ + } + + if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ + { + g_reset_wait_obj(done_obj); + xrdp_listen_delete_done_pro(self); + } + } + } + else + { + g_writeln("xrdp_listen_main_loop: listen error, possible port " + "already in use"); + } - self->status = 1; - if (xrdp_listen_get_port_address(port, sizeof(port), - address, sizeof(address), - &tcp_nodelay, &tcp_keepalive, - self->startup_params) != 0) - { - g_writeln("xrdp_listen_main_loop: xrdp_listen_get_port failed"); self->status = -1; - return 1; - } - /*Create socket*/ - error = trans_listen_address(self->listen_trans, port, address); - if (error == 0) - { - if(tcp_nodelay) - { - if(g_tcp_set_no_delay(self->listen_trans->sck)) - { - g_writeln("Error setting tcp_nodelay"); - } - } - if(tcp_keepalive) - { - if(g_tcp_set_keepalive(self->listen_trans->sck)) - { - g_writeln("Error setting tcp_keepalive"); - } - } - self->listen_trans->trans_conn_in = xrdp_listen_conn_in; - self->listen_trans->callback_data = self; - term_obj = g_get_term_event(); /*Global termination event */ - sync_obj = g_get_sync_event(); - done_obj = self->pro_done_event; - cont = 1; - while (cont) - { - /* build the wait obj list */ - robjs_count = 0; - robjs[robjs_count++] = term_obj; - robjs[robjs_count++] = sync_obj; - robjs[robjs_count++] = done_obj; - timeout = -1; - if (trans_get_wait_objs(self->listen_trans, robjs, &robjs_count) != 0) - { - g_writeln("Listening socket is in wrong state we terminate listener") ; - break; - } - /* wait - timeout -1 means wait indefinitely*/ - if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) - { - /* error, should not get here */ - g_sleep(100); - } - if (g_is_wait_obj_set(term_obj)) /* termination called */ - { - break; - } - if (g_is_wait_obj_set(sync_obj)) /* some function must be processed by this thread */ - { - g_reset_wait_obj(sync_obj); - g_process_waiting_function(); /* run the function */ - } - if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ - { - g_reset_wait_obj(done_obj); - /* a process has died remove it from lists*/ - xrdp_listen_delete_done_pro(self); - } - /* Run the callback when accept() returns a new socket*/ - if (trans_check_wait_objs(self->listen_trans) != 0) - { - break; - } - } - /* stop listening */ - trans_delete(self->listen_trans); - self->listen_trans = 0; - /* second loop to wait for all process threads to close */ - cont = 1; - while (cont) - { - if (self->process_list->count == 0) - { - break; - } - timeout = -1; - /* build the wait obj list */ - robjs_count = 0; - robjs[robjs_count++] = sync_obj; - robjs[robjs_count++] = done_obj; - /* wait - timeout -1 means wait indefinitely*/ - if (g_obj_wait(robjs, robjs_count, 0, 0, timeout) != 0) - { - /* error, should not get here */ - g_sleep(100); - } - if (g_is_wait_obj_set(sync_obj)) /* some function must be processed by this thread */ - { - g_reset_wait_obj(sync_obj); - g_process_waiting_function(); /* run the function that is waiting*/ - } - if (g_is_wait_obj_set(done_obj)) /* pro_done_event */ - { - g_reset_wait_obj(done_obj); - xrdp_listen_delete_done_pro(self); - } - } - } - else - { - g_writeln("xrdp_listen_main_loop: listen error, possible port " - "already in use"); - } - self->status = -1; - return 0; + return 0; } diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index 69d3721f..fc4cf125 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - main login window and login help window - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * main login window and login help window + */ #include "xrdp.h" #define ACCESS @@ -27,571 +25,616 @@ /*****************************************************************************/ /* all login help screen events go here */ static int DEFAULT_CC -xrdp_wm_login_help_notify(struct xrdp_bitmap* wnd, - struct xrdp_bitmap* sender, +xrdp_wm_login_help_notify(struct xrdp_bitmap *wnd, + struct xrdp_bitmap *sender, int msg, long param1, long param2) { - struct xrdp_painter* p; + struct xrdp_painter *p; - if (wnd == 0) - { - return 0; - } - if (sender == 0) - { - return 0; - } - if (wnd->owner == 0) - { - return 0; - } - if (msg == 1) /* click */ - { - if (sender->id == 1) /* ok button */ + if (wnd == 0) { - if (sender->owner->notify != 0) - { - wnd->owner->notify(wnd->owner, wnd, 100, 1, 0); /* ok */ - } + return 0; } - } - else if (msg == WM_PAINT) /* 3 */ - { - p = (struct xrdp_painter*)param1; - if (p != 0) + + if (sender == 0) { - p->fg_color = wnd->wm->black; - xrdp_painter_draw_text(p, wnd, 10, 30, "You must be authenticated \ + return 0; + } + + if (wnd->owner == 0) + { + return 0; + } + + if (msg == 1) /* click */ + { + if (sender->id == 1) /* ok button */ + { + if (sender->owner->notify != 0) + { + wnd->owner->notify(wnd->owner, wnd, 100, 1, 0); /* ok */ + } + } + } + else if (msg == WM_PAINT) /* 3 */ + { + p = (struct xrdp_painter *)param1; + + if (p != 0) + { + p->fg_color = wnd->wm->black; + xrdp_painter_draw_text(p, wnd, 10, 30, "You must be authenticated \ before using this"); - xrdp_painter_draw_text(p, wnd, 10, 46, "session."); - xrdp_painter_draw_text(p, wnd, 10, 78, "Enter a valid username in \ + xrdp_painter_draw_text(p, wnd, 10, 46, "session."); + xrdp_painter_draw_text(p, wnd, 10, 78, "Enter a valid username in \ the username edit box."); - xrdp_painter_draw_text(p, wnd, 10, 94, "Enter the password in \ + xrdp_painter_draw_text(p, wnd, 10, 94, "Enter the password in \ the password edit box."); - xrdp_painter_draw_text(p, wnd, 10, 110, "Both the username and \ + xrdp_painter_draw_text(p, wnd, 10, 110, "Both the username and \ password are case"); - xrdp_painter_draw_text(p, wnd, 10, 126, "sensitive."); - xrdp_painter_draw_text(p, wnd, 10, 158, "Contact your system \ + xrdp_painter_draw_text(p, wnd, 10, 126, "sensitive."); + xrdp_painter_draw_text(p, wnd, 10, 158, "Contact your system \ administrator if you are"); - xrdp_painter_draw_text(p, wnd, 10, 174, "having problems \ + xrdp_painter_draw_text(p, wnd, 10, 174, "having problems \ logging on."); + } } - } - return 0; + + return 0; } #if 0 /*****************************************************************************/ static int DEFAULT_CC -xrdp_wm_popup_notify(struct xrdp_bitmap* wnd, - struct xrdp_bitmap* sender, +xrdp_wm_popup_notify(struct xrdp_bitmap *wnd, + struct xrdp_bitmap *sender, int msg, int param1, int param2) { - return 0; + return 0; } #endif /*****************************************************************************/ int APP_CC -xrdp_wm_delete_all_childs(struct xrdp_wm* self) +xrdp_wm_delete_all_childs(struct xrdp_wm *self) { - int index; - struct xrdp_bitmap* b; - struct xrdp_rect rect; + int index; + struct xrdp_bitmap *b; + struct xrdp_rect rect; - for (index = self->screen->child_list->count - 1; index >= 0; index--) - { - b = (struct xrdp_bitmap*)list_get_item(self->screen->child_list, index); - MAKERECT(rect, b->left, b->top, b->width, b->height); - xrdp_bitmap_delete(b); - xrdp_bitmap_invalidate(self->screen, &rect); - } - return 0; -} - -/*****************************************************************************/ -static int APP_CC -set_mod_data_item(struct xrdp_mod_data* mod, char* name, char* value) -{ - int index; - - for (index = 0; index < mod->names->count; index++) - { - if (g_strncmp(name, (char*)list_get_item(mod->names, index), 255) == 0) + for (index = self->screen->child_list->count - 1; index >= 0; index--) { - list_remove_item(mod->values, index); - list_insert_item(mod->values, index, (long)g_strdup(value)); + b = (struct xrdp_bitmap *)list_get_item(self->screen->child_list, index); + MAKERECT(rect, b->left, b->top, b->width, b->height); + xrdp_bitmap_delete(b); + xrdp_bitmap_invalidate(self->screen, &rect); } - } - return 0; + + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_wm_help_clicked(struct xrdp_bitmap* wnd) +set_mod_data_item(struct xrdp_mod_data *mod, char *name, char *value) { - struct xrdp_bitmap* help; - struct xrdp_bitmap* but; + int index; - /* create help screen */ - help = xrdp_bitmap_create(DEFAULT_WND_HELP_W, DEFAULT_WND_HELP_H, wnd->wm->screen->bpp, - WND_TYPE_WND, wnd->wm); - list_insert_item(wnd->wm->screen->child_list, 0, (long)help); - help->parent = wnd->wm->screen; - help->owner = wnd; - wnd->modal_dialog = help; - help->bg_color = wnd->wm->grey; - help->left = wnd->wm->screen->width / 2 - help->width / 2; - help->top = wnd->wm->screen->height / 2 - help->height / 2; - help->notify = xrdp_wm_login_help_notify; - set_string(&help->caption1, "Login help"); - /* ok button */ - but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, wnd->wm->screen->bpp, - WND_TYPE_BUTTON, wnd->wm); - list_insert_item(help->child_list, 0, (long)but); - but->parent = help; - but->owner = help; - but->left = ((DEFAULT_WND_HELP_W / 2) - (DEFAULT_BUTTON_W / 2)); /* center */ - but->top = DEFAULT_WND_HELP_H - DEFAULT_BUTTON_H - 15; - but->id = 1; - but->tab_stop = 1; - set_string(&but->caption1, "OK"); - /* draw it */ - help->focused_control = but; - help->default_button = but; - help->esc_button = but; - xrdp_bitmap_invalidate(help, 0); - xrdp_wm_set_focused(wnd->wm, help); - return 0; -} - -/*****************************************************************************/ -static int APP_CC -xrdp_wm_cancel_clicked(struct xrdp_bitmap* wnd) -{ - if (wnd != 0) - { - if (wnd->wm != 0) + for (index = 0; index < mod->names->count; index++) { - if (wnd->wm->pro_layer != 0) - { - g_set_wait_obj(wnd->wm->pro_layer->self_term_event); - } + if (g_strncmp(name, (char *)list_get_item(mod->names, index), 255) == 0) + { + list_remove_item(mod->values, index); + list_insert_item(mod->values, index, (long)g_strdup(value)); + } } - } - return 0; + + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_wm_ok_clicked(struct xrdp_bitmap* wnd) +xrdp_wm_help_clicked(struct xrdp_bitmap *wnd) { - struct xrdp_bitmap* combo; - struct xrdp_bitmap* label; - struct xrdp_bitmap* edit; - struct xrdp_wm* wm; - struct xrdp_mod_data* mod_data; - int i; + struct xrdp_bitmap *help; + struct xrdp_bitmap *but; - wm = wnd->wm; - combo = xrdp_bitmap_get_child_by_id(wnd, 6); - if (combo != 0) - { - mod_data = (struct xrdp_mod_data*) - list_get_item(combo->data_list, combo->item_index); - if (mod_data != 0) + /* create help screen */ + help = xrdp_bitmap_create(DEFAULT_WND_HELP_W, DEFAULT_WND_HELP_H, wnd->wm->screen->bpp, + WND_TYPE_WND, wnd->wm); + list_insert_item(wnd->wm->screen->child_list, 0, (long)help); + help->parent = wnd->wm->screen; + help->owner = wnd; + wnd->modal_dialog = help; + help->bg_color = wnd->wm->grey; + help->left = wnd->wm->screen->width / 2 - help->width / 2; + help->top = wnd->wm->screen->height / 2 - help->height / 2; + help->notify = xrdp_wm_login_help_notify; + set_string(&help->caption1, "Login help"); + /* ok button */ + but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, wnd->wm->screen->bpp, + WND_TYPE_BUTTON, wnd->wm); + list_insert_item(help->child_list, 0, (long)but); + but->parent = help; + but->owner = help; + but->left = ((DEFAULT_WND_HELP_W / 2) - (DEFAULT_BUTTON_W / 2)); /* center */ + but->top = DEFAULT_WND_HELP_H - DEFAULT_BUTTON_H - 15; + but->id = 1; + but->tab_stop = 1; + set_string(&but->caption1, "OK"); + /* draw it */ + help->focused_control = but; + help->default_button = but; + help->esc_button = but; + xrdp_bitmap_invalidate(help, 0); + xrdp_wm_set_focused(wnd->wm, help); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_wm_cancel_clicked(struct xrdp_bitmap *wnd) +{ + if (wnd != 0) { - /* get the user typed values */ - i = 100; - label = xrdp_bitmap_get_child_by_id(wnd, i); - edit = xrdp_bitmap_get_child_by_id(wnd, i + 1); - while (label != 0 && edit != 0) - { - set_mod_data_item(mod_data, label->caption1, edit->caption1); - i += 2; - label = xrdp_bitmap_get_child_by_id(wnd, i); - edit = xrdp_bitmap_get_child_by_id(wnd, i + 1); - } - list_delete(wm->mm->login_names); - list_delete(wm->mm->login_values); - wm->mm->login_names = list_create(); - wm->mm->login_names->auto_free = 1; - wm->mm->login_values = list_create(); - wm->mm->login_values->auto_free = 1; - /* gota copy these cause dialog gets freed */ - list_append_list_strdup(mod_data->names, wm->mm->login_names, 0); - list_append_list_strdup(mod_data->values, wm->mm->login_values, 0); - xrdp_wm_set_login_mode(wm, 2); + if (wnd->wm != 0) + { + if (wnd->wm->pro_layer != 0) + { + g_set_wait_obj(wnd->wm->pro_layer->self_term_event); + } + } } - } - else - { - log_message(LOG_LEVEL_ERROR,"Combo is 0 - potential programming error"); - } - return 0; + + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_wm_ok_clicked(struct xrdp_bitmap *wnd) +{ + struct xrdp_bitmap *combo; + struct xrdp_bitmap *label; + struct xrdp_bitmap *edit; + struct xrdp_wm *wm; + struct xrdp_mod_data *mod_data; + int i; + + wm = wnd->wm; + combo = xrdp_bitmap_get_child_by_id(wnd, 6); + + if (combo != 0) + { + mod_data = (struct xrdp_mod_data *) + list_get_item(combo->data_list, combo->item_index); + + if (mod_data != 0) + { + /* get the user typed values */ + i = 100; + label = xrdp_bitmap_get_child_by_id(wnd, i); + edit = xrdp_bitmap_get_child_by_id(wnd, i + 1); + + while (label != 0 && edit != 0) + { + set_mod_data_item(mod_data, label->caption1, edit->caption1); + i += 2; + label = xrdp_bitmap_get_child_by_id(wnd, i); + edit = xrdp_bitmap_get_child_by_id(wnd, i + 1); + } + + list_delete(wm->mm->login_names); + list_delete(wm->mm->login_values); + wm->mm->login_names = list_create(); + wm->mm->login_names->auto_free = 1; + wm->mm->login_values = list_create(); + wm->mm->login_values->auto_free = 1; + /* gota copy these cause dialog gets freed */ + list_append_list_strdup(mod_data->names, wm->mm->login_names, 0); + list_append_list_strdup(mod_data->values, wm->mm->login_values, 0); + xrdp_wm_set_login_mode(wm, 2); + } + } + else + { + log_message(LOG_LEVEL_ERROR, "Combo is 0 - potential programming error"); + } + + return 0; } /******************************************************************************/ static int APP_CC -xrdp_wm_show_edits(struct xrdp_wm* self, struct xrdp_bitmap* combo) +xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo) { - int count; - int index; - int insert_index; - int username_set; - char* name; - char* value; - struct xrdp_mod_data* mod; - struct xrdp_bitmap* b; + int count; + int index; + int insert_index; + int username_set; + char *name; + char *value; + struct xrdp_mod_data *mod; + struct xrdp_bitmap *b; - username_set = 0; - /* free labels and edits, cause we gota create them */ - /* creation or combo changed */ - for (index = 100; index < 200; index++) - { - b = xrdp_bitmap_get_child_by_id(combo->parent, index); - xrdp_bitmap_delete(b); - } + username_set = 0; - insert_index = list_index_of(self->login_window->child_list, - (long)combo); - insert_index++; - mod = (struct xrdp_mod_data*) - list_get_item(combo->data_list, combo->item_index); - if (mod != 0) - { - count = 0; - for (index = 0; index < mod->names->count; index++) + /* free labels and edits, cause we gota create them */ + /* creation or combo changed */ + for (index = 100; index < 200; index++) { - value = (char*)list_get_item(mod->values, index); - if (g_strncmp("ask", value, 3) == 0) - { - /* label */ - b = xrdp_bitmap_create(95, DEFAULT_EDIT_H, self->screen->bpp, - WND_TYPE_LABEL, self); - list_insert_item(self->login_window->child_list, insert_index, - (long)b); - insert_index++; - b->parent = self->login_window; - b->owner = self->login_window; - b->left = self->login_window->width >= DEFAULT_WND_LOGIN_W ? 155 : 5; - b->top = DEFAULT_ELEMENT_TOP + DEFAULT_COMBO_H + 5 + (DEFAULT_EDIT_H+5) * count; - b->id = 100 + 2 * count; - name = (char*)list_get_item(mod->names, index); - set_string(&b->caption1, name); - /* edit */ - b = xrdp_bitmap_create(DEFAULT_EDIT_W, DEFAULT_EDIT_H, self->screen->bpp, - WND_TYPE_EDIT, self); - list_insert_item(self->login_window->child_list, insert_index, - (long)b); - insert_index++; - b->parent = self->login_window; - b->owner = self->login_window; - b->left = self->login_window->width >= DEFAULT_WND_LOGIN_W ? DEFAULT_WND_LOGIN_W - DEFAULT_EDIT_W - 30 : 70; - b->top = DEFAULT_ELEMENT_TOP + DEFAULT_COMBO_H + 5 + (DEFAULT_EDIT_H+5) * count; - b->id = 100 + 2 * count + 1; - b->pointer = 1; - b->tab_stop = 1; - b->caption1 = (char*)g_malloc(256, 1); - g_strncpy(b->caption1, value + 3, 255); - b->edit_pos = g_mbstowcs(0, b->caption1, 0); - if (self->login_window->focused_control == 0) - { - self->login_window->focused_control = b; - } - if (g_strncmp(name, "username", 255) == 0) - { - g_strncpy(b->caption1, self->session->client_info->username, 255); - b->edit_pos = g_mbstowcs(0, b->caption1, 0); - if (b->edit_pos > 0) - { - username_set = 1; - } - } -#ifdef ACCESS - if ((g_strncmp(name, "password", 255) == 0) || (g_strncmp(name, "pampassword", 255) == 0)) -#else - if (g_strncmp(name, "password", 255) == 0) -#endif - { - b->password_char = '*'; - if (username_set) - { - if (b->parent != 0) - { - b->parent->focused_control = b; - } - } - } - count++; - } + b = xrdp_bitmap_get_child_by_id(combo->parent, index); + xrdp_bitmap_delete(b); } - } - return 0; + + insert_index = list_index_of(self->login_window->child_list, + (long)combo); + insert_index++; + mod = (struct xrdp_mod_data *) + list_get_item(combo->data_list, combo->item_index); + + if (mod != 0) + { + count = 0; + + for (index = 0; index < mod->names->count; index++) + { + value = (char *)list_get_item(mod->values, index); + + if (g_strncmp("ask", value, 3) == 0) + { + /* label */ + b = xrdp_bitmap_create(95, DEFAULT_EDIT_H, self->screen->bpp, + WND_TYPE_LABEL, self); + list_insert_item(self->login_window->child_list, insert_index, + (long)b); + insert_index++; + b->parent = self->login_window; + b->owner = self->login_window; + b->left = self->login_window->width >= DEFAULT_WND_LOGIN_W ? 155 : 5; + b->top = DEFAULT_ELEMENT_TOP + DEFAULT_COMBO_H + 5 + (DEFAULT_EDIT_H + 5) * count; + b->id = 100 + 2 * count; + name = (char *)list_get_item(mod->names, index); + set_string(&b->caption1, name); + /* edit */ + b = xrdp_bitmap_create(DEFAULT_EDIT_W, DEFAULT_EDIT_H, self->screen->bpp, + WND_TYPE_EDIT, self); + list_insert_item(self->login_window->child_list, insert_index, + (long)b); + insert_index++; + b->parent = self->login_window; + b->owner = self->login_window; + b->left = self->login_window->width >= DEFAULT_WND_LOGIN_W ? DEFAULT_WND_LOGIN_W - DEFAULT_EDIT_W - 30 : 70; + b->top = DEFAULT_ELEMENT_TOP + DEFAULT_COMBO_H + 5 + (DEFAULT_EDIT_H + 5) * count; + b->id = 100 + 2 * count + 1; + b->pointer = 1; + b->tab_stop = 1; + b->caption1 = (char *)g_malloc(256, 1); + g_strncpy(b->caption1, value + 3, 255); + b->edit_pos = g_mbstowcs(0, b->caption1, 0); + + if (self->login_window->focused_control == 0) + { + self->login_window->focused_control = b; + } + + if (g_strncmp(name, "username", 255) == 0) + { + g_strncpy(b->caption1, self->session->client_info->username, 255); + b->edit_pos = g_mbstowcs(0, b->caption1, 0); + + if (b->edit_pos > 0) + { + username_set = 1; + } + } + +#ifdef ACCESS + + if ((g_strncmp(name, "password", 255) == 0) || (g_strncmp(name, "pampassword", 255) == 0)) +#else + if (g_strncmp(name, "password", 255) == 0) +#endif + { + b->password_char = '*'; + + if (username_set) + { + if (b->parent != 0) + { + b->parent->focused_control = b; + } + } + } + + count++; + } + } + } + + return 0; } /*****************************************************************************/ /* all login screen events go here */ static int DEFAULT_CC -xrdp_wm_login_notify(struct xrdp_bitmap* wnd, - struct xrdp_bitmap* sender, +xrdp_wm_login_notify(struct xrdp_bitmap *wnd, + struct xrdp_bitmap *sender, int msg, long param1, long param2) { - struct xrdp_bitmap* b; - struct xrdp_rect rect; - int i; + struct xrdp_bitmap *b; + struct xrdp_rect rect; + int i; + + if (wnd->modal_dialog != 0 && msg != 100) + { + return 0; + } + + if (msg == 1) /* click */ + { + if (sender->id == 1) /* help button */ + { + xrdp_wm_help_clicked(wnd); + } + else if (sender->id == 2) /* cancel button */ + { + xrdp_wm_cancel_clicked(wnd); + } + else if (sender->id == 3) /* ok button */ + { + xrdp_wm_ok_clicked(wnd); + } + } + else if (msg == 2) /* mouse move */ + { + } + else if (msg == 100) /* modal result is done */ + { + i = list_index_of(wnd->wm->screen->child_list, (long)sender); + + if (i >= 0) + { + b = (struct xrdp_bitmap *) + list_get_item(wnd->wm->screen->child_list, i); + list_remove_item(sender->wm->screen->child_list, i); + MAKERECT(rect, b->left, b->top, b->width, b->height); + xrdp_bitmap_invalidate(wnd->wm->screen, &rect); + xrdp_bitmap_delete(sender); + wnd->modal_dialog = 0; + xrdp_wm_set_focused(wnd->wm, wnd); + } + } + else if (msg == CB_ITEMCHANGE) /* combo box change */ + { + xrdp_wm_show_edits(wnd->wm, sender); + xrdp_bitmap_invalidate(wnd, 0); /* invalidate the whole dialog for now */ + } - if (wnd->modal_dialog != 0 && msg != 100) - { return 0; - } - if (msg == 1) /* click */ - { - if (sender->id == 1) /* help button */ - { - xrdp_wm_help_clicked(wnd); - } - else if (sender->id == 2) /* cancel button */ - { - xrdp_wm_cancel_clicked(wnd); - } - else if (sender->id == 3) /* ok button */ - { - xrdp_wm_ok_clicked(wnd); - } - } - else if (msg == 2) /* mouse move */ - { - } - else if (msg == 100) /* modal result is done */ - { - i = list_index_of(wnd->wm->screen->child_list, (long)sender); - if (i >= 0) - { - b = (struct xrdp_bitmap*) - list_get_item(wnd->wm->screen->child_list, i); - list_remove_item(sender->wm->screen->child_list, i); - MAKERECT(rect, b->left, b->top, b->width, b->height); - xrdp_bitmap_invalidate(wnd->wm->screen, &rect); - xrdp_bitmap_delete(sender); - wnd->modal_dialog = 0; - xrdp_wm_set_focused(wnd->wm, wnd); - } - } - else if (msg == CB_ITEMCHANGE) /* combo box change */ - { - xrdp_wm_show_edits(wnd->wm, sender); - xrdp_bitmap_invalidate(wnd, 0); /* invalidate the whole dialog for now */ - } - return 0; } /******************************************************************************/ static int APP_CC -xrdp_wm_login_fill_in_combo(struct xrdp_wm* self, struct xrdp_bitmap* b) +xrdp_wm_login_fill_in_combo(struct xrdp_wm *self, struct xrdp_bitmap *b) { - struct list* sections; - struct list* section_names; - struct list* section_values; - int fd; - int i; - int j; - char* p; - char* q; - char* r; - char name[256]; - char cfg_file[256]; - struct xrdp_mod_data* mod_data; + struct list *sections; + struct list *section_names; + struct list *section_values; + int fd; + int i; + int j; + char *p; + char *q; + char *r; + char name[256]; + char cfg_file[256]; + struct xrdp_mod_data *mod_data; - sections = list_create(); - sections->auto_free = 1; - section_names = list_create(); - section_names->auto_free = 1; - section_values = list_create(); - section_values->auto_free = 1; - g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); - fd = g_file_open(cfg_file); /* xrdp.ini */ - if (fd < 1) - { - log_message(LOG_LEVEL_ERROR,"Could not read xrdp ini file %s", cfg_file); - } - file_read_sections(fd, sections); - for (i = 0; i < sections->count; i++) - { - p = (char*)list_get_item(sections, i); - file_read_section(fd, p, section_names, section_values); - if ((g_strncmp(p, "globals", 255) == 0) - ||(g_strncmp(p, "channels", 255) == 0) - ||(g_strncmp(p, "Logging", 255) == 0)) + sections = list_create(); + sections->auto_free = 1; + section_names = list_create(); + section_names->auto_free = 1; + section_values = list_create(); + section_values->auto_free = 1; + g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + fd = g_file_open(cfg_file); /* xrdp.ini */ + + if (fd < 1) { + log_message(LOG_LEVEL_ERROR, "Could not read xrdp ini file %s", cfg_file); } - else + + file_read_sections(fd, sections); + + for (i = 0; i < sections->count; i++) { - g_strncpy(name, p, 255); - mod_data = (struct xrdp_mod_data*) - g_malloc(sizeof(struct xrdp_mod_data), 1); - mod_data->names = list_create(); - mod_data->names->auto_free = 1; - mod_data->values = list_create(); - mod_data->values->auto_free = 1; - for (j = 0; j < section_names->count; j++) - { - q = (char*)list_get_item(section_names, j); - r = (char*)list_get_item(section_values, j); - if (g_strncmp("name", q, 255) == 0) + p = (char *)list_get_item(sections, i); + file_read_section(fd, p, section_names, section_values); + + if ((g_strncmp(p, "globals", 255) == 0) + || (g_strncmp(p, "channels", 255) == 0) + || (g_strncmp(p, "Logging", 255) == 0)) { - g_strncpy(name, r, 255); } - list_add_item(mod_data->names, (long)g_strdup(q)); - list_add_item(mod_data->values, (long)g_strdup(r)); - } - list_add_item(b->string_list, (long)g_strdup(name)); - list_add_item(b->data_list, (long)mod_data); + else + { + g_strncpy(name, p, 255); + mod_data = (struct xrdp_mod_data *) + g_malloc(sizeof(struct xrdp_mod_data), 1); + mod_data->names = list_create(); + mod_data->names->auto_free = 1; + mod_data->values = list_create(); + mod_data->values->auto_free = 1; + + for (j = 0; j < section_names->count; j++) + { + q = (char *)list_get_item(section_names, j); + r = (char *)list_get_item(section_values, j); + + if (g_strncmp("name", q, 255) == 0) + { + g_strncpy(name, r, 255); + } + + list_add_item(mod_data->names, (long)g_strdup(q)); + list_add_item(mod_data->values, (long)g_strdup(r)); + } + + list_add_item(b->string_list, (long)g_strdup(name)); + list_add_item(b->data_list, (long)mod_data); + } } - } - g_file_close(fd); - list_delete(sections); - list_delete(section_names); - list_delete(section_values); - return 0; + + g_file_close(fd); + list_delete(sections); + list_delete(section_names); + list_delete(section_values); + return 0; } /******************************************************************************/ int APP_CC -xrdp_login_wnd_create(struct xrdp_wm* self) +xrdp_login_wnd_create(struct xrdp_wm *self) { - struct xrdp_bitmap* but; - struct xrdp_bitmap* combo; - char file_path[256]; - int log_width; - int log_height; - int regular; + struct xrdp_bitmap *but; + struct xrdp_bitmap *combo; + char file_path[256]; + int log_width; + int log_height; + int regular; - log_width = DEFAULT_WND_LOGIN_W; - log_height = DEFAULT_WND_LOGIN_H; - regular = 1; - if (self->screen->width < log_width) - { - if (self->screen->width < 240) - { - log_width = self->screen->width - 4; - } - else - { - log_width = 240; - } - regular = 0; - } - /* draw login window */ - self->login_window = xrdp_bitmap_create(log_width, log_height, self->screen->bpp, - WND_TYPE_WND, self); - list_add_item(self->screen->child_list, (long)self->login_window); - self->login_window->parent = self->screen; - self->login_window->owner = self->screen; - self->login_window->bg_color = self->grey; - self->login_window->left = self->screen->width / 2 - - self->login_window->width / 2; - self->login_window->top = self->screen->height / 2 - - self->login_window->height / 2; - self->login_window->notify = xrdp_wm_login_notify; - set_string(&self->login_window->caption1, "Login to xrdp"); - if (regular) - { - /* image */ - but = xrdp_bitmap_create(4, 4, self->screen->bpp, WND_TYPE_IMAGE, self); - if (self->screen->bpp > 8) - { - g_snprintf(file_path, 255, "%s/xrdp24b.bmp", XRDP_SHARE_PATH); - } - else - { - g_snprintf(file_path, 255, "%s/xrdp256.bmp", XRDP_SHARE_PATH); - } - xrdp_bitmap_load(but, file_path, self->palette); - but->parent = self->screen; - but->owner = self->screen; - but->left = self->screen->width - but->width; - but->top = self->screen->height - but->height; - list_add_item(self->screen->child_list, (long)but); + log_width = DEFAULT_WND_LOGIN_W; + log_height = DEFAULT_WND_LOGIN_H; + regular = 1; - /* image */ - but = xrdp_bitmap_create(4, 4, self->screen->bpp, WND_TYPE_IMAGE, self); - if (self->screen->bpp > 8) + if (self->screen->width < log_width) { - g_snprintf(file_path, 255, "%s/ad24b.bmp", XRDP_SHARE_PATH); + if (self->screen->width < 240) + { + log_width = self->screen->width - 4; + } + else + { + log_width = 240; + } + + regular = 0; } - else + + /* draw login window */ + self->login_window = xrdp_bitmap_create(log_width, log_height, self->screen->bpp, + WND_TYPE_WND, self); + list_add_item(self->screen->child_list, (long)self->login_window); + self->login_window->parent = self->screen; + self->login_window->owner = self->screen; + self->login_window->bg_color = self->grey; + self->login_window->left = self->screen->width / 2 - + self->login_window->width / 2; + self->login_window->top = self->screen->height / 2 - + self->login_window->height / 2; + self->login_window->notify = xrdp_wm_login_notify; + set_string(&self->login_window->caption1, "Login to xrdp"); + + if (regular) { - g_snprintf(file_path, 255, "%s/ad256.bmp", XRDP_SHARE_PATH); + /* image */ + but = xrdp_bitmap_create(4, 4, self->screen->bpp, WND_TYPE_IMAGE, self); + + if (self->screen->bpp > 8) + { + g_snprintf(file_path, 255, "%s/xrdp24b.bmp", XRDP_SHARE_PATH); + } + else + { + g_snprintf(file_path, 255, "%s/xrdp256.bmp", XRDP_SHARE_PATH); + } + + xrdp_bitmap_load(but, file_path, self->palette); + but->parent = self->screen; + but->owner = self->screen; + but->left = self->screen->width - but->width; + but->top = self->screen->height - but->height; + list_add_item(self->screen->child_list, (long)but); + + /* image */ + but = xrdp_bitmap_create(4, 4, self->screen->bpp, WND_TYPE_IMAGE, self); + + if (self->screen->bpp > 8) + { + g_snprintf(file_path, 255, "%s/ad24b.bmp", XRDP_SHARE_PATH); + } + else + { + g_snprintf(file_path, 255, "%s/ad256.bmp", XRDP_SHARE_PATH); + } + + xrdp_bitmap_load(but, file_path, self->palette); + but->parent = self->login_window; + but->owner = self->login_window; + but->left = 10; + but->top = 30; + list_add_item(self->login_window->child_list, (long)but); } - xrdp_bitmap_load(but, file_path, self->palette); + + /* label */ + but = xrdp_bitmap_create(60, DEFAULT_EDIT_H, self->screen->bpp, WND_TYPE_LABEL, self); + list_add_item(self->login_window->child_list, (long)but); but->parent = self->login_window; but->owner = self->login_window; - but->left = 10; - but->top = 30; - list_add_item(self->login_window->child_list, (long)but); - } + but->left = regular ? 155 : 5; + but->top = DEFAULT_ELEMENT_TOP; + set_string(&but->caption1, "Module"); - /* label */ - but = xrdp_bitmap_create(60, DEFAULT_EDIT_H, self->screen->bpp, WND_TYPE_LABEL, self); - list_add_item(self->login_window->child_list, (long)but); - but->parent = self->login_window; - but->owner = self->login_window; - but->left = regular ? 155 : 5; - but->top = DEFAULT_ELEMENT_TOP; - set_string(&but->caption1, "Module"); + /* combo */ + combo = xrdp_bitmap_create(DEFAULT_COMBO_W, DEFAULT_COMBO_H, self->screen->bpp, WND_TYPE_COMBO, self); + list_add_item(self->login_window->child_list, (long)combo); + combo->parent = self->login_window; + combo->owner = self->login_window; + combo->left = regular ? DEFAULT_WND_LOGIN_W - DEFAULT_COMBO_W - 30 : 70; + combo->top = DEFAULT_ELEMENT_TOP; + combo->id = 6; + combo->tab_stop = 1; + xrdp_wm_login_fill_in_combo(self, combo); - /* combo */ - combo = xrdp_bitmap_create(DEFAULT_COMBO_W, DEFAULT_COMBO_H, self->screen->bpp, WND_TYPE_COMBO, self); - list_add_item(self->login_window->child_list, (long)combo); - combo->parent = self->login_window; - combo->owner = self->login_window; - combo->left = regular ? DEFAULT_WND_LOGIN_W - DEFAULT_COMBO_W - 30 : 70; - combo->top = DEFAULT_ELEMENT_TOP; - combo->id = 6; - combo->tab_stop = 1; - xrdp_wm_login_fill_in_combo(self, combo); - - /* button */ - but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); - list_add_item(self->login_window->child_list, (long)but); - but->parent = self->login_window; - but->owner = self->login_window; - but->left = regular ? DEFAULT_WND_LOGIN_W - ((DEFAULT_BUTTON_W+10)*3) - 10 : 30; - but->top = DEFAULT_WND_LOGIN_H - DEFAULT_BUTTON_H - 15; - but->id = 3; - set_string(&but->caption1, "OK"); - but->tab_stop = 1; - self->login_window->default_button = but; - - /* button */ - but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); - list_add_item(self->login_window->child_list, (long)but); - but->parent = self->login_window; - but->owner = self->login_window; - but->left = regular ? DEFAULT_WND_LOGIN_W - ((DEFAULT_BUTTON_W+10)*2) - 10 : ((log_width - 30) - DEFAULT_BUTTON_W); - but->top = DEFAULT_WND_LOGIN_H - DEFAULT_BUTTON_H - 15; - but->id = 2; - set_string(&but->caption1, "Cancel"); - but->tab_stop = 1; - self->login_window->esc_button = but; - - if (regular) - { /* button */ but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); list_add_item(self->login_window->child_list, (long)but); but->parent = self->login_window; but->owner = self->login_window; - but->left = DEFAULT_WND_LOGIN_W - (DEFAULT_BUTTON_W+10) - 10; + but->left = regular ? DEFAULT_WND_LOGIN_W - ((DEFAULT_BUTTON_W + 10) * 3) - 10 : 30; but->top = DEFAULT_WND_LOGIN_H - DEFAULT_BUTTON_H - 15; - but->id = 1; - set_string(&but->caption1, "Help"); + but->id = 3; + set_string(&but->caption1, "OK"); but->tab_stop = 1; - } + self->login_window->default_button = but; - /* labels and edits */ - xrdp_wm_show_edits(self, combo); + /* button */ + but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); + list_add_item(self->login_window->child_list, (long)but); + but->parent = self->login_window; + but->owner = self->login_window; + but->left = regular ? DEFAULT_WND_LOGIN_W - ((DEFAULT_BUTTON_W + 10) * 2) - 10 : ((log_width - 30) - DEFAULT_BUTTON_W); + but->top = DEFAULT_WND_LOGIN_H - DEFAULT_BUTTON_H - 15; + but->id = 2; + set_string(&but->caption1, "Cancel"); + but->tab_stop = 1; + self->login_window->esc_button = but; - return 0; + if (regular) + { + /* button */ + but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); + list_add_item(self->login_window->child_list, (long)but); + but->parent = self->login_window; + but->owner = self->login_window; + but->left = DEFAULT_WND_LOGIN_W - (DEFAULT_BUTTON_W + 10) - 10; + but->top = DEFAULT_WND_LOGIN_H - DEFAULT_BUTTON_H - 15; + but->id = 1; + set_string(&but->caption1, "Help"); + but->tab_stop = 1; + } + + /* labels and edits */ + xrdp_wm_show_edits(self, combo); + + return 0; } diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 0b764cc6..e13854ae 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1,42 +1,40 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - module manager - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * module manager + */ #include "xrdp.h" #include "log.h" #define ACCESS /*****************************************************************************/ -struct xrdp_mm* APP_CC -xrdp_mm_create(struct xrdp_wm* owner) +struct xrdp_mm *APP_CC +xrdp_mm_create(struct xrdp_wm *owner) { - struct xrdp_mm* self; + struct xrdp_mm *self; - self = (struct xrdp_mm*)g_malloc(sizeof(struct xrdp_mm), 1); - self->wm = owner; - self->login_names = list_create(); - self->login_names->auto_free = 1; - self->login_values = list_create(); - self->login_values->auto_free = 1; - return self; + self = (struct xrdp_mm *)g_malloc(sizeof(struct xrdp_mm), 1); + self->wm = owner; + self->login_names = list_create(); + self->login_names->auto_free = 1; + self->login_values = list_create(); + self->login_values->auto_free = 1; + return self; } /*****************************************************************************/ @@ -44,7 +42,7 @@ xrdp_mm_create(struct xrdp_wm* owner) static long DEFAULT_CC xrdp_mm_sync_unload(long param1, long param2) { - return g_free_library(param1); + return g_free_library(param1); } /*****************************************************************************/ @@ -52,170 +50,178 @@ xrdp_mm_sync_unload(long param1, long param2) static long DEFAULT_CC xrdp_mm_sync_load(long param1, long param2) { - long rv; - char* libname; + long rv; + char *libname; - libname = (char*)param1; - rv = g_load_library(libname); - return rv; + libname = (char *)param1; + rv = g_load_library(libname); + return rv; } /*****************************************************************************/ static void APP_CC -xrdp_mm_module_cleanup(struct xrdp_mm* self) +xrdp_mm_module_cleanup(struct xrdp_mm *self) { - g_writeln("xrdp_mm_module_cleanup"); - if (self->mod != 0) - { - if (self->mod_exit != 0) + g_writeln("xrdp_mm_module_cleanup"); + + if (self->mod != 0) { - /* let the module cleanup */ - self->mod_exit(self->mod); + if (self->mod_exit != 0) + { + /* let the module cleanup */ + self->mod_exit(self->mod); + } } - } - if (self->mod_handle != 0) - { - /* Let the main thread unload the module.*/ - g_xrdp_sync(xrdp_mm_sync_unload, self->mod_handle, 0); - } - trans_delete(self->chan_trans); - self->chan_trans = 0; - self->chan_trans_up = 0; - self->mod_init = 0; - self->mod_exit = 0; - self->mod = 0; - self->mod_handle = 0; + + if (self->mod_handle != 0) + { + /* Let the main thread unload the module.*/ + g_xrdp_sync(xrdp_mm_sync_unload, self->mod_handle, 0); + } + + trans_delete(self->chan_trans); + self->chan_trans = 0; + self->chan_trans_up = 0; + self->mod_init = 0; + self->mod_exit = 0; + self->mod = 0; + self->mod_handle = 0; } /*****************************************************************************/ void APP_CC -xrdp_mm_delete(struct xrdp_mm* self) +xrdp_mm_delete(struct xrdp_mm *self) { - if (self == 0) - { - return; - } - /* free any module stuff */ - xrdp_mm_module_cleanup(self); - trans_delete(self->sesman_trans); - self->sesman_trans = 0; - self->sesman_trans_up = 0; - list_delete(self->login_names); - list_delete(self->login_values); - g_free(self); + if (self == 0) + { + return; + } + + /* free any module stuff */ + xrdp_mm_module_cleanup(self); + trans_delete(self->sesman_trans); + self->sesman_trans = 0; + self->sesman_trans_up = 0; + list_delete(self->login_names); + list_delete(self->login_values); + g_free(self); } /*****************************************************************************/ /* Send login information to sesman */ static int APP_CC -xrdp_mm_send_login(struct xrdp_mm* self) +xrdp_mm_send_login(struct xrdp_mm *self) { - struct stream* s; - int rv; - int index; - int count; - int xserverbpp; - char* username; - char* password; - char* name; - char* value; + struct stream *s; + int rv; + int index; + int count; + int xserverbpp; + char *username; + char *password; + char *name; + char *value; - xrdp_wm_log_msg(self->wm, "sending login info to session manager, " - "please wait..."); - username = 0; - password = 0; - self->code = 0; - xserverbpp = 0; - count = self->login_names->count; - for (index = 0; index < count; index++) - { - name = (char*)list_get_item(self->login_names, index); - value = (char*)list_get_item(self->login_values, index); - if (g_strcasecmp(name, "username") == 0) + xrdp_wm_log_msg(self->wm, "sending login info to session manager, " + "please wait..."); + username = 0; + password = 0; + self->code = 0; + xserverbpp = 0; + count = self->login_names->count; + + for (index = 0; index < count; index++) { - username = value; + name = (char *)list_get_item(self->login_names, index); + value = (char *)list_get_item(self->login_values, index); + + if (g_strcasecmp(name, "username") == 0) + { + username = value; + } + else if (g_strcasecmp(name, "password") == 0) + { + password = value; + } + else if (g_strcasecmp(name, "lib") == 0) + { + if ((g_strcasecmp(value, "libxup.so") == 0) || + (g_strcasecmp(value, "xup.dll") == 0)) + { + self->code = 10; + } + } + else if (g_strcasecmp(name, "xserverbpp") == 0) + { + xserverbpp = g_atoi(value); + } } - else if (g_strcasecmp(name, "password") == 0) + + if ((username == 0) || (password == 0)) { - password = value; + xrdp_wm_log_msg(self->wm, "Error finding username and password"); + return 1; } - else if (g_strcasecmp(name, "lib") == 0) + + s = trans_get_out_s(self->sesman_trans, 8192); + s_push_layer(s, channel_hdr, 8); + /* this code is either 0 for Xvnc or 10 for X11rdp */ + out_uint16_be(s, self->code); + index = g_strlen(username); + out_uint16_be(s, index); + out_uint8a(s, username, index); + index = g_strlen(password); + + out_uint16_be(s, index); + out_uint8a(s, password, index); + out_uint16_be(s, self->wm->screen->width); + out_uint16_be(s, self->wm->screen->height); + + if (xserverbpp > 0) { - if ((g_strcasecmp(value, "libxup.so") == 0) || - (g_strcasecmp(value, "xup.dll") == 0)) - { - self->code = 10; - } + out_uint16_be(s, xserverbpp); } - else if (g_strcasecmp(name, "xserverbpp") == 0) + else { - xserverbpp = g_atoi(value); + out_uint16_be(s, self->wm->screen->bpp); } - } - if ((username == 0) || (password == 0)) - { - xrdp_wm_log_msg(self->wm, "Error finding username and password"); - return 1; - } - s = trans_get_out_s(self->sesman_trans, 8192); - s_push_layer(s, channel_hdr, 8); - /* this code is either 0 for Xvnc or 10 for X11rdp */ - out_uint16_be(s, self->code); - index = g_strlen(username); - out_uint16_be(s, index); - out_uint8a(s, username, index); - index = g_strlen(password); + /* send domain */ + index = g_strlen(self->wm->client_info->domain); + out_uint16_be(s, index); + out_uint8a(s, self->wm->client_info->domain, index); - out_uint16_be(s, index); - out_uint8a(s, password, index); - out_uint16_be(s, self->wm->screen->width); - out_uint16_be(s, self->wm->screen->height); + /* send program / shell */ + index = g_strlen(self->wm->client_info->program); + out_uint16_be(s, index); + out_uint8a(s, self->wm->client_info->program, index); - if (xserverbpp > 0) - { - out_uint16_be(s, xserverbpp); - } - else - { - out_uint16_be(s, self->wm->screen->bpp); - } + /* send directory */ + index = g_strlen(self->wm->client_info->directory); + out_uint16_be(s, index); + out_uint8a(s, self->wm->client_info->directory, index); - /* send domain */ - index = g_strlen(self->wm->client_info->domain); - out_uint16_be(s, index); - out_uint8a(s, self->wm->client_info->domain, index); + /* send client ip */ + index = g_strlen(self->wm->client_info->client_ip); + out_uint16_be(s, index); + out_uint8a(s, self->wm->client_info->client_ip, index); - /* send program / shell */ - index = g_strlen(self->wm->client_info->program); - out_uint16_be(s, index); - out_uint8a(s, self->wm->client_info->program, index); + s_mark_end(s); - /* send directory */ - index = g_strlen(self->wm->client_info->directory); - out_uint16_be(s, index); - out_uint8a(s, self->wm->client_info->directory, index); + s_pop_layer(s, channel_hdr); + /* Version 0 of the protocol to sesman is currently used by XRDP */ + out_uint32_be(s, 0); /* version */ + index = (int)(s->end - s->data); + out_uint32_be(s, index); /* size */ - /* send client ip */ - index = g_strlen(self->wm->client_info->client_ip); - out_uint16_be(s, index); - out_uint8a(s, self->wm->client_info->client_ip, index); + rv = trans_force_write(self->sesman_trans); - s_mark_end(s); + if (rv != 0) + { + xrdp_wm_log_msg(self->wm, "xrdp_mm_send_login: xrdp_mm_send_login failed"); + } - s_pop_layer(s, channel_hdr); - /* Version 0 of the protocol to sesman is currently used by XRDP */ - out_uint32_be(s, 0); /* version */ - index = (int)(s->end - s->data); - out_uint32_be(s, index); /* size */ - - rv = trans_force_write(self->sesman_trans); - - if (rv != 0) { - xrdp_wm_log_msg(self->wm, "xrdp_mm_send_login: xrdp_mm_send_login failed"); - } - - return rv; + return rv; } /*****************************************************************************/ @@ -224,744 +230,828 @@ xrdp_mm_send_login(struct xrdp_mm* self) then it copies the corisponding login_values item into 'dest' 'dest' must be at least 'dest_len' + 1 bytes in size */ static int APP_CC -xrdp_mm_get_value(struct xrdp_mm* self, char* aname, char* dest, int dest_len) +xrdp_mm_get_value(struct xrdp_mm *self, char *aname, char *dest, int dest_len) { - char* name; - char* value; - int index; - int count; - int rv; + char *name; + char *value; + int index; + int count; + int rv; - rv = 1; - /* find the library name */ - dest[0] = 0; - count = self->login_names->count; - for (index = 0; index < count; index++) - { - name = (char*)list_get_item(self->login_names, index); - value = (char*)list_get_item(self->login_values, index); - if ((name == 0) || (value == 0)) - { - break; - } - if (g_strcasecmp(name, aname) == 0) - { - g_strncpy(dest, value, dest_len); - rv = 0; - } - } + rv = 1; + /* find the library name */ + dest[0] = 0; + count = self->login_names->count; - return rv; + for (index = 0; index < count; index++) + { + name = (char *)list_get_item(self->login_names, index); + value = (char *)list_get_item(self->login_values, index); + + if ((name == 0) || (value == 0)) + { + break; + } + + if (g_strcasecmp(name, aname) == 0) + { + g_strncpy(dest, value, dest_len); + rv = 0; + } + } + + return rv; } /*****************************************************************************/ static int APP_CC -xrdp_mm_setup_mod1(struct xrdp_mm* self) +xrdp_mm_setup_mod1(struct xrdp_mm *self) { - void* func; - char lib[256]; - char text[256]; + void *func; + char lib[256]; + char text[256]; - if (self == 0) - { - return 1; - } - lib[0] = 0; - if (xrdp_mm_get_value(self, "lib", lib, 255) != 0) - { - g_snprintf(text, 255, "no library name specified in xrdp.ini, please add " - "lib=libxrdp-vnc.so or similar"); - xrdp_wm_log_msg(self->wm, text); - - return 1; - } - if (lib[0] == 0) - { - g_snprintf(text, 255, "empty library name specified in xrdp.ini, please " - "add lib=libxrdp-vnc.so or similar"); - xrdp_wm_log_msg(self->wm, text); - - return 1; - } - if (self->mod_handle == 0) - { - /* Let the main thread load the lib,*/ - self->mod_handle = g_xrdp_sync(xrdp_mm_sync_load, (long)lib, 0); - if (self->mod_handle != 0) + if (self == 0) { - func = g_get_proc_address(self->mod_handle, "mod_init"); - if (func == 0) - { - func = g_get_proc_address(self->mod_handle, "_mod_init"); - } - if (func == 0) - { - g_snprintf(text, 255, "error finding proc mod_init in %s, not a valid " - "xrdp backend", lib); + return 1; + } + + lib[0] = 0; + + if (xrdp_mm_get_value(self, "lib", lib, 255) != 0) + { + g_snprintf(text, 255, "no library name specified in xrdp.ini, please add " + "lib=libxrdp-vnc.so or similar"); xrdp_wm_log_msg(self->wm, text); - } - self->mod_init = (struct xrdp_mod* (*)(void))func; - func = g_get_proc_address(self->mod_handle, "mod_exit"); - if (func == 0) - { - func = g_get_proc_address(self->mod_handle, "_mod_exit"); - } - if (func == 0) - { - g_snprintf(text, 255, "error finding proc mod_exit in %s, not a valid " - "xrdp backend", lib); + + return 1; + } + + if (lib[0] == 0) + { + g_snprintf(text, 255, "empty library name specified in xrdp.ini, please " + "add lib=libxrdp-vnc.so or similar"); xrdp_wm_log_msg(self->wm, text); - } - self->mod_exit = (int (*)(struct xrdp_mod*))func; - if ((self->mod_init != 0) && (self->mod_exit != 0)) - { - self->mod = self->mod_init(); - if (self->mod != 0) - { - g_writeln("loaded module '%s' ok, interface size %d, version %d", lib, - self->mod->size, self->mod->version); - } - }else{ - g_writeln("no mod_init or mod_exit address found"); - } - } - else - { - g_snprintf(text, 255, "error loading %s specified in xrdp.ini, please " - "add a valid entry like lib=libxrdp-vnc.so or similar", lib); - xrdp_wm_log_msg(self->wm, text); - return 1; - } - if (self->mod != 0) - { - self->mod->wm = (long)(self->wm); - self->mod->server_begin_update = server_begin_update; - self->mod->server_end_update = server_end_update; - self->mod->server_bell_trigger = server_bell_trigger; - self->mod->server_fill_rect = server_fill_rect; - self->mod->server_screen_blt = server_screen_blt; - self->mod->server_paint_rect = server_paint_rect; - self->mod->server_set_pointer = server_set_pointer; - self->mod->server_palette = server_palette; - self->mod->server_msg = server_msg; - self->mod->server_is_term = server_is_term; - self->mod->server_set_clip = server_set_clip; - self->mod->server_reset_clip = server_reset_clip; - self->mod->server_set_fgcolor = server_set_fgcolor; - self->mod->server_set_bgcolor = server_set_bgcolor; - self->mod->server_set_opcode = server_set_opcode; - self->mod->server_set_mixmode = server_set_mixmode; - self->mod->server_set_brush = server_set_brush; - self->mod->server_set_pen = server_set_pen; - self->mod->server_draw_line = server_draw_line; - self->mod->server_add_char = server_add_char; - self->mod->server_draw_text = server_draw_text; - self->mod->server_reset = server_reset; - self->mod->server_query_channel = server_query_channel; - self->mod->server_get_channel_id = server_get_channel_id; - self->mod->server_send_to_channel = server_send_to_channel; - self->mod->server_create_os_surface = server_create_os_surface; - self->mod->server_switch_os_surface = server_switch_os_surface; - self->mod->server_delete_os_surface = server_delete_os_surface; - self->mod->server_paint_rect_os = server_paint_rect_os; - self->mod->server_set_hints = server_set_hints; - self->mod->server_window_new_update = server_window_new_update; - self->mod->server_window_delete = server_window_delete; - self->mod->server_window_icon = server_window_icon; - self->mod->server_window_cached_icon = server_window_cached_icon; - self->mod->server_notify_new_update = server_notify_new_update; - self->mod->server_notify_delete = server_notify_delete; - self->mod->server_monitored_desktop = server_monitored_desktop; - } - } - /* id self->mod is null, there must be a problem */ - if (self->mod == 0) - { - DEBUG(("problem loading lib in xrdp_mm_setup_mod1")); - return 1; - } - return 0; -} -/*****************************************************************************/ -static int APP_CC -xrdp_mm_setup_mod2(struct xrdp_mm* self) -{ - char text[256]; - char* name; - char* value; - int i; - int rv; - int key_flags; - int device_flags; - int use_uds; - - rv = 1; /* failure */ - g_memset(text, 0, sizeof(text)); - if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) - { - if (self->mod->mod_start(self->mod, self->wm->screen->width, - self->wm->screen->height, - self->wm->screen->bpp) != 0) - { - g_set_wait_obj(self->wm->pro_layer->self_term_event); /* kill session */ + return 1; } - } - if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) - { - if (self->display > 0) + + if (self->mod_handle == 0) { - if (self->code == 0) /* Xvnc */ - { - g_snprintf(text, 255, "%d", 5900 + self->display); - } - else if (self->code == 10) /* X11rdp */ - { - use_uds = 1; - if (xrdp_mm_get_value(self, "ip", text, 255) == 0) + /* Let the main thread load the lib,*/ + self->mod_handle = g_xrdp_sync(xrdp_mm_sync_load, (long)lib, 0); + + if (self->mod_handle != 0) { - if (g_strcmp(text, "127.0.0.1") != 0) - { - use_uds = 0; - } - } - if (use_uds) - { - g_snprintf(text, 255, "/tmp/.xrdp/xrdp_display_%d", self->display); + func = g_get_proc_address(self->mod_handle, "mod_init"); + + if (func == 0) + { + func = g_get_proc_address(self->mod_handle, "_mod_init"); + } + + if (func == 0) + { + g_snprintf(text, 255, "error finding proc mod_init in %s, not a valid " + "xrdp backend", lib); + xrdp_wm_log_msg(self->wm, text); + } + + self->mod_init = (struct xrdp_mod * ( *)(void))func; + func = g_get_proc_address(self->mod_handle, "mod_exit"); + + if (func == 0) + { + func = g_get_proc_address(self->mod_handle, "_mod_exit"); + } + + if (func == 0) + { + g_snprintf(text, 255, "error finding proc mod_exit in %s, not a valid " + "xrdp backend", lib); + xrdp_wm_log_msg(self->wm, text); + } + + self->mod_exit = (int ( *)(struct xrdp_mod *))func; + + if ((self->mod_init != 0) && (self->mod_exit != 0)) + { + self->mod = self->mod_init(); + + if (self->mod != 0) + { + g_writeln("loaded module '%s' ok, interface size %d, version %d", lib, + self->mod->size, self->mod->version); + } + } + else + { + g_writeln("no mod_init or mod_exit address found"); + } } else { - g_snprintf(text, 255, "%d", 6200 + self->display); + g_snprintf(text, 255, "error loading %s specified in xrdp.ini, please " + "add a valid entry like lib=libxrdp-vnc.so or similar", lib); + xrdp_wm_log_msg(self->wm, text); + return 1; } - } - else - { - g_set_wait_obj(self->wm->pro_layer->self_term_event); /* kill session */ - } - } - } - if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) - { - /* this adds the port to the end of the list, it will already be in - the list as -1 - the module should use the last one */ - if (g_strlen(text) > 0) - { - list_add_item(self->login_names, (long)g_strdup("port")); - list_add_item(self->login_values, (long)g_strdup(text)); - } - /* always set these */ - self->mod->mod_set_param(self->mod, "client_info", - (char*)(self->wm->session->client_info)); + if (self->mod != 0) + { + self->mod->wm = (long)(self->wm); + self->mod->server_begin_update = server_begin_update; + self->mod->server_end_update = server_end_update; + self->mod->server_bell_trigger = server_bell_trigger; + self->mod->server_fill_rect = server_fill_rect; + self->mod->server_screen_blt = server_screen_blt; + self->mod->server_paint_rect = server_paint_rect; + self->mod->server_set_pointer = server_set_pointer; + self->mod->server_palette = server_palette; + self->mod->server_msg = server_msg; + self->mod->server_is_term = server_is_term; + self->mod->server_set_clip = server_set_clip; + self->mod->server_reset_clip = server_reset_clip; + self->mod->server_set_fgcolor = server_set_fgcolor; + self->mod->server_set_bgcolor = server_set_bgcolor; + self->mod->server_set_opcode = server_set_opcode; + self->mod->server_set_mixmode = server_set_mixmode; + self->mod->server_set_brush = server_set_brush; + self->mod->server_set_pen = server_set_pen; + self->mod->server_draw_line = server_draw_line; + self->mod->server_add_char = server_add_char; + self->mod->server_draw_text = server_draw_text; + self->mod->server_reset = server_reset; + self->mod->server_query_channel = server_query_channel; + self->mod->server_get_channel_id = server_get_channel_id; + self->mod->server_send_to_channel = server_send_to_channel; + self->mod->server_create_os_surface = server_create_os_surface; + self->mod->server_switch_os_surface = server_switch_os_surface; + self->mod->server_delete_os_surface = server_delete_os_surface; + self->mod->server_paint_rect_os = server_paint_rect_os; + self->mod->server_set_hints = server_set_hints; + self->mod->server_window_new_update = server_window_new_update; + self->mod->server_window_delete = server_window_delete; + self->mod->server_window_icon = server_window_icon; + self->mod->server_window_cached_icon = server_window_cached_icon; + self->mod->server_notify_new_update = server_notify_new_update; + self->mod->server_notify_delete = server_notify_delete; + self->mod->server_monitored_desktop = server_monitored_desktop; + } + } - name = self->wm->session->client_info->hostname; - self->mod->mod_set_param(self->mod, "hostname", name); - g_snprintf(text, 255, "%d", self->wm->session->client_info->keylayout); - self->mod->mod_set_param(self->mod, "keylayout", text); - for (i = 0; i < self->login_names->count; i++) + /* id self->mod is null, there must be a problem */ + if (self->mod == 0) { - name = (char*)list_get_item(self->login_names, i); - value = (char*)list_get_item(self->login_values, i); - self->mod->mod_set_param(self->mod, name, value); + DEBUG(("problem loading lib in xrdp_mm_setup_mod1")); + return 1; } - /* connect */ - if (self->mod->mod_connect(self->mod) == 0) + + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_mm_setup_mod2(struct xrdp_mm *self) +{ + char text[256]; + char *name; + char *value; + int i; + int rv; + int key_flags; + int device_flags; + int use_uds; + + rv = 1; /* failure */ + g_memset(text, 0, sizeof(text)); + + if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) { - rv = 0; /* connect success */ + if (self->mod->mod_start(self->mod, self->wm->screen->width, + self->wm->screen->height, + self->wm->screen->bpp) != 0) + { + g_set_wait_obj(self->wm->pro_layer->self_term_event); /* kill session */ + } } - } - if (rv == 0) - { - /* sync modifiers */ - key_flags = 0; - device_flags = 0; - if (self->wm->scroll_lock) + + if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) { - key_flags |= 1; + if (self->display > 0) + { + if (self->code == 0) /* Xvnc */ + { + g_snprintf(text, 255, "%d", 5900 + self->display); + } + else if (self->code == 10) /* X11rdp */ + { + use_uds = 1; + + if (xrdp_mm_get_value(self, "ip", text, 255) == 0) + { + if (g_strcmp(text, "127.0.0.1") != 0) + { + use_uds = 0; + } + } + + if (use_uds) + { + g_snprintf(text, 255, "/tmp/.xrdp/xrdp_display_%d", self->display); + } + else + { + g_snprintf(text, 255, "%d", 6200 + self->display); + } + } + else + { + g_set_wait_obj(self->wm->pro_layer->self_term_event); /* kill session */ + } + } } - if (self->wm->num_lock) + + if (!g_is_wait_obj_set(self->wm->pro_layer->self_term_event)) { - key_flags |= 2; + /* this adds the port to the end of the list, it will already be in + the list as -1 + the module should use the last one */ + if (g_strlen(text) > 0) + { + list_add_item(self->login_names, (long)g_strdup("port")); + list_add_item(self->login_values, (long)g_strdup(text)); + } + + /* always set these */ + + self->mod->mod_set_param(self->mod, "client_info", + (char *)(self->wm->session->client_info)); + + name = self->wm->session->client_info->hostname; + self->mod->mod_set_param(self->mod, "hostname", name); + g_snprintf(text, 255, "%d", self->wm->session->client_info->keylayout); + self->mod->mod_set_param(self->mod, "keylayout", text); + + for (i = 0; i < self->login_names->count; i++) + { + name = (char *)list_get_item(self->login_names, i); + value = (char *)list_get_item(self->login_values, i); + self->mod->mod_set_param(self->mod, name, value); + } + + /* connect */ + if (self->mod->mod_connect(self->mod) == 0) + { + rv = 0; /* connect success */ + } } - if (self->wm->caps_lock) + + if (rv == 0) { - key_flags |= 4; + /* sync modifiers */ + key_flags = 0; + device_flags = 0; + + if (self->wm->scroll_lock) + { + key_flags |= 1; + } + + if (self->wm->num_lock) + { + key_flags |= 2; + } + + if (self->wm->caps_lock) + { + key_flags |= 4; + } + + if (self->mod != 0) + { + if (self->mod->mod_event != 0) + { + self->mod->mod_event(self->mod, 17, key_flags, device_flags, + key_flags, device_flags); + } + } } - if (self->mod != 0) - { - if (self->mod->mod_event != 0) - { - self->mod->mod_event(self->mod, 17, key_flags, device_flags, - key_flags, device_flags); - } - } - } - return rv; + + return rv; } /*****************************************************************************/ /* returns error send a list of channels to the channel handler */ static int APP_CC -xrdp_mm_trans_send_channel_setup(struct xrdp_mm* self, struct trans* trans) +xrdp_mm_trans_send_channel_setup(struct xrdp_mm *self, struct trans *trans) { - int index; - int chan_id; - int chan_flags; - int size; - struct stream* s; - char chan_name[256]; + int index; + int chan_id; + int chan_flags; + int size; + struct stream *s; + char chan_name[256]; - g_memset(chan_name,0,sizeof(char) * 256); + g_memset(chan_name, 0, sizeof(char) * 256); - s = trans_get_out_s(trans, 8192); - if (s == 0) - { - return 1; - } - s_push_layer(s, iso_hdr, 8); - s_push_layer(s, mcs_hdr, 8); - s_push_layer(s, sec_hdr, 2); - index = 0; - while (libxrdp_query_channel(self->wm->session, index, chan_name, - &chan_flags) == 0) - { - chan_id = libxrdp_get_channel_id(self->wm->session, chan_name); - out_uint8a(s, chan_name, 8); - out_uint16_le(s, chan_id); - out_uint16_le(s, chan_flags); - index++; - } - s_mark_end(s); - s_pop_layer(s, sec_hdr); - out_uint16_le(s, index); - s_pop_layer(s, mcs_hdr); - size = (int)(s->end - s->p); - out_uint32_le(s, 3); /* msg id */ - out_uint32_le(s, size); /* msg size */ - s_pop_layer(s, iso_hdr); - size = (int)(s->end - s->p); - out_uint32_le(s, 0); /* version */ - out_uint32_le(s, size); /* block size */ - return trans_force_write(trans); + s = trans_get_out_s(trans, 8192); + + if (s == 0) + { + return 1; + } + + s_push_layer(s, iso_hdr, 8); + s_push_layer(s, mcs_hdr, 8); + s_push_layer(s, sec_hdr, 2); + index = 0; + + while (libxrdp_query_channel(self->wm->session, index, chan_name, + &chan_flags) == 0) + { + chan_id = libxrdp_get_channel_id(self->wm->session, chan_name); + out_uint8a(s, chan_name, 8); + out_uint16_le(s, chan_id); + out_uint16_le(s, chan_flags); + index++; + } + + s_mark_end(s); + s_pop_layer(s, sec_hdr); + out_uint16_le(s, index); + s_pop_layer(s, mcs_hdr); + size = (int)(s->end - s->p); + out_uint32_le(s, 3); /* msg id */ + out_uint32_le(s, size); /* msg size */ + s_pop_layer(s, iso_hdr); + size = (int)(s->end - s->p); + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, size); /* block size */ + return trans_force_write(trans); } /*****************************************************************************/ /* returns error */ static int APP_CC -xrdp_mm_trans_send_channel_data_response(struct xrdp_mm* self, - struct trans* trans) +xrdp_mm_trans_send_channel_data_response(struct xrdp_mm *self, + struct trans *trans) { - struct stream* s; + struct stream *s; - s = trans_get_out_s(trans, 8192); - if (s == 0) - { - return 1; - } - out_uint32_le(s, 0); /* version */ - out_uint32_le(s, 8 + 8); /* size */ - out_uint32_le(s, 7); /* msg id */ - out_uint32_le(s, 8); /* size */ - s_mark_end(s); - return trans_force_write(trans); + s = trans_get_out_s(trans, 8192); + + if (s == 0) + { + return 1; + } + + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8); /* size */ + out_uint32_le(s, 7); /* msg id */ + out_uint32_le(s, 8); /* size */ + s_mark_end(s); + return trans_force_write(trans); } /*****************************************************************************/ /* returns error init is done, sent channel setup */ static int APP_CC -xrdp_mm_trans_process_init_response(struct xrdp_mm* self, struct trans* trans) +xrdp_mm_trans_process_init_response(struct xrdp_mm *self, struct trans *trans) { - return xrdp_mm_trans_send_channel_setup(self, trans); + return xrdp_mm_trans_send_channel_setup(self, trans); } /*****************************************************************************/ /* returns error data coming in from the channel handler, send it to the client */ static int APP_CC -xrdp_mm_trans_process_channel_data(struct xrdp_mm* self, struct trans* trans) +xrdp_mm_trans_process_channel_data(struct xrdp_mm *self, struct trans *trans) { - struct stream* s; - int size; - int total_size; - int chan_id; - int chan_flags; - int rv; + struct stream *s; + int size; + int total_size; + int chan_id; + int chan_flags; + int rv; - s = trans_get_in_s(trans); - if (s == 0) - { - return 1; - } - in_uint16_le(s, chan_id); - in_uint16_le(s, chan_flags); - in_uint16_le(s, size); - in_uint32_le(s, total_size); - rv = xrdp_mm_trans_send_channel_data_response(self, trans); - if (rv == 0) - { - rv = libxrdp_send_to_channel(self->wm->session, chan_id, s->p, size, total_size, - chan_flags); - } - return rv; + s = trans_get_in_s(trans); + + if (s == 0) + { + return 1; + } + + in_uint16_le(s, chan_id); + in_uint16_le(s, chan_flags); + in_uint16_le(s, size); + in_uint32_le(s, total_size); + rv = xrdp_mm_trans_send_channel_data_response(self, trans); + + if (rv == 0) + { + rv = libxrdp_send_to_channel(self->wm->session, chan_id, s->p, size, total_size, + chan_flags); + } + + return rv; } /*****************************************************************************/ /* returns error process a message for the channel handler */ static int APP_CC -xrdp_mm_chan_process_msg(struct xrdp_mm* self, struct trans* trans, - struct stream* s) +xrdp_mm_chan_process_msg(struct xrdp_mm *self, struct trans *trans, + struct stream *s) { - int rv; - int id; - int size; - char* next_msg; + int rv; + int id; + int size; + char *next_msg; - rv = 0; - while (s_check_rem(s, 8)) - { - next_msg = s->p; - in_uint32_le(s, id); - in_uint32_le(s, size); - next_msg += size; - switch (id) + rv = 0; + + while (s_check_rem(s, 8)) { - case 2: /* channel init response */ - rv = xrdp_mm_trans_process_init_response(self, trans); - break; - case 4: /* channel setup response */ - break; - case 6: /* channel data response */ - break; - case 8: /* channel data */ - rv = xrdp_mm_trans_process_channel_data(self, trans); - break; - default: - g_writeln("xrdp_mm_chan_process_msg: unknown id %d", id); - break; + next_msg = s->p; + in_uint32_le(s, id); + in_uint32_le(s, size); + next_msg += size; + + switch (id) + { + case 2: /* channel init response */ + rv = xrdp_mm_trans_process_init_response(self, trans); + break; + case 4: /* channel setup response */ + break; + case 6: /* channel data response */ + break; + case 8: /* channel data */ + rv = xrdp_mm_trans_process_channel_data(self, trans); + break; + default: + g_writeln("xrdp_mm_chan_process_msg: unknown id %d", id); + break; + } + + if (rv != 0) + { + break; + } + + s->p = next_msg; } - if (rv != 0) - { - break; - } - s->p = next_msg; - } - return rv; + + return rv; } /*****************************************************************************/ /* this is callback from trans obj returns error */ static int APP_CC -xrdp_mm_chan_data_in(struct trans* trans) +xrdp_mm_chan_data_in(struct trans *trans) { - struct xrdp_mm* self; - struct stream* s; - int id; - int size; - int error; + struct xrdp_mm *self; + struct stream *s; + int id; + int size; + int error; - if (trans == 0) - { - return 1; - } - self = (struct xrdp_mm*)(trans->callback_data); - s = trans_get_in_s(trans); - if (s == 0) - { - return 1; - } - in_uint32_le(s, id); - in_uint32_le(s, size); - error = trans_force_read(trans, size - 8); - if (error == 0) - { - /* here, the entire message block is read in, process it */ - error = xrdp_mm_chan_process_msg(self, trans, s); - } - return error; + if (trans == 0) + { + return 1; + } + + self = (struct xrdp_mm *)(trans->callback_data); + s = trans_get_in_s(trans); + + if (s == 0) + { + return 1; + } + + in_uint32_le(s, id); + in_uint32_le(s, size); + error = trans_force_read(trans, size - 8); + + if (error == 0) + { + /* here, the entire message block is read in, process it */ + error = xrdp_mm_chan_process_msg(self, trans, s); + } + + return error; } /*****************************************************************************/ static int APP_CC -xrdp_mm_chan_send_init(struct xrdp_mm* self) +xrdp_mm_chan_send_init(struct xrdp_mm *self) { - struct stream* s; + struct stream *s; - s = trans_get_out_s(self->chan_trans, 8192); - if (s == 0) - { - return 1; - } - out_uint32_le(s, 0); /* version */ - out_uint32_le(s, 8 + 8); /* size */ - out_uint32_le(s, 1); /* msg id */ - out_uint32_le(s, 8); /* size */ - s_mark_end(s); - return trans_force_write(self->chan_trans); + s = trans_get_out_s(self->chan_trans, 8192); + + if (s == 0) + { + return 1; + } + + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8); /* size */ + out_uint32_le(s, 1); /* msg id */ + out_uint32_le(s, 8); /* size */ + s_mark_end(s); + return trans_force_write(self->chan_trans); } /*****************************************************************************/ /* connect to chansrv */ static int APP_CC -xrdp_mm_connect_chansrv(struct xrdp_mm* self, char* ip, char* port) +xrdp_mm_connect_chansrv(struct xrdp_mm *self, char *ip, char *port) { - int index; + int index; - self->usechansrv = 1; + self->usechansrv = 1; - /* connect channel redir */ - if ((ip == 0) || (g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) - { - /* unix socket */ - self->chan_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); - } - else - { - /* tcp */ - self->chan_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); - } - self->chan_trans->trans_data_in = xrdp_mm_chan_data_in; - self->chan_trans->header_size = 8; - self->chan_trans->callback_data = self; - /* try to connect up to 4 times */ - for (index = 0; index < 4; index++) - { - if (trans_connect(self->chan_trans, ip, port, 3000) == 0) + /* connect channel redir */ + if ((ip == 0) || (g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) { - self->chan_trans_up = 1; - break; - } - g_sleep(1000); - g_writeln("xrdp_mm_connect_chansrv: connect failed " - "trying again..."); - } - if (!(self->chan_trans_up)) - { - g_writeln("xrdp_mm_connect_chansrv: error in trans_connect " - "chan"); - } - if (self->chan_trans_up) - { - if (xrdp_mm_chan_send_init(self) != 0) - { - g_writeln("xrdp_mm_connect_chansrv: error in " - "xrdp_mm_chan_send_init"); + /* unix socket */ + self->chan_trans = trans_create(TRANS_MODE_UNIX, 8192, 8192); } else { - g_writeln("xrdp_mm_connect_chansrv: chansrv connect successful"); + /* tcp */ + self->chan_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); } - } - return 0; + + self->chan_trans->trans_data_in = xrdp_mm_chan_data_in; + self->chan_trans->header_size = 8; + self->chan_trans->callback_data = self; + + /* try to connect up to 4 times */ + for (index = 0; index < 4; index++) + { + if (trans_connect(self->chan_trans, ip, port, 3000) == 0) + { + self->chan_trans_up = 1; + break; + } + + g_sleep(1000); + g_writeln("xrdp_mm_connect_chansrv: connect failed " + "trying again..."); + } + + if (!(self->chan_trans_up)) + { + g_writeln("xrdp_mm_connect_chansrv: error in trans_connect " + "chan"); + } + + if (self->chan_trans_up) + { + if (xrdp_mm_chan_send_init(self) != 0) + { + g_writeln("xrdp_mm_connect_chansrv: error in " + "xrdp_mm_chan_send_init"); + } + else + { + g_writeln("xrdp_mm_connect_chansrv: chansrv connect successful"); + } + } + + return 0; } -static void cleanup_sesman_connection(struct xrdp_mm* self) +static void cleanup_sesman_connection(struct xrdp_mm *self) { - self->delete_sesman_trans = 1; - self->connected_state = 0; - if (self->wm->login_mode != 10) - { - xrdp_wm_set_login_mode(self->wm, 11); - xrdp_mm_module_cleanup(self); - } + self->delete_sesman_trans = 1; + self->connected_state = 0; + + if (self->wm->login_mode != 10) + { + xrdp_wm_set_login_mode(self->wm, 11); + xrdp_mm_module_cleanup(self); + } } /*****************************************************************************/ static int APP_CC -xrdp_mm_process_login_response(struct xrdp_mm* self, struct stream* s) +xrdp_mm_process_login_response(struct xrdp_mm *self, struct stream *s) { - int ok; - int display; - int rv; - char text[256]; - char ip[256]; - char port[256]; + int ok; + int display; + int rv; + char text[256]; + char ip[256]; + char port[256]; - rv = 0; - in_uint16_be(s, ok); - in_uint16_be(s, display); - if (ok) - { - self->display = display; - g_snprintf(text, 255, "xrdp_mm_process_login_response: login successful " - "for display %d", display); - xrdp_wm_log_msg(self->wm, text); - if (xrdp_mm_setup_mod1(self) == 0) + rv = 0; + in_uint16_be(s, ok); + in_uint16_be(s, display); + + if (ok) { - if (xrdp_mm_setup_mod2(self) == 0) - { - xrdp_mm_get_value(self, "ip", ip, 255); - xrdp_wm_set_login_mode(self->wm, 10); - self->wm->dragging = 0; - /* connect channel redir */ - if ((ip == 0) || (g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) + self->display = display; + g_snprintf(text, 255, "xrdp_mm_process_login_response: login successful " + "for display %d", display); + xrdp_wm_log_msg(self->wm, text); + + if (xrdp_mm_setup_mod1(self) == 0) { - g_snprintf(port, 255, "/tmp/.xrdp/xrdp_chansrv_socket_%d", 7200 + display); + if (xrdp_mm_setup_mod2(self) == 0) + { + xrdp_mm_get_value(self, "ip", ip, 255); + xrdp_wm_set_login_mode(self->wm, 10); + self->wm->dragging = 0; + + /* connect channel redir */ + if ((ip == 0) || (g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0)) + { + g_snprintf(port, 255, "/tmp/.xrdp/xrdp_chansrv_socket_%d", 7200 + display); + } + else + { + g_snprintf(port, 255, "%d", 7200 + display); + } + + xrdp_mm_connect_chansrv(self, ip, port); + } } - else - { - g_snprintf(port, 255, "%d", 7200 + display); - } - xrdp_mm_connect_chansrv(self, ip, port); - } } - } - else - { - xrdp_wm_log_msg(self->wm, "xrdp_mm_process_login_response: " - "login failed"); - } - cleanup_sesman_connection(self); - return rv; + else + { + xrdp_wm_log_msg(self->wm, "xrdp_mm_process_login_response: " + "login failed"); + } + + cleanup_sesman_connection(self); + return rv; } /*****************************************************************************/ static int -xrdp_mm_get_sesman_port(char* port, int port_bytes) +xrdp_mm_get_sesman_port(char *port, int port_bytes) { - int fd; - int error; - int index; - char* val; - char cfg_file[256]; - struct list* names; - struct list* values; + int fd; + int error; + int index; + char *val; + char cfg_file[256]; + struct list *names; + struct list *values; - g_memset(cfg_file,0,sizeof(char) * 256); - /* default to port 3350 */ - g_strncpy(port, "3350", port_bytes - 1); - /* see if port is in xrdp.ini file */ - g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); - fd = g_file_open(cfg_file); - if (fd > 0) - { - names = list_create(); - names->auto_free = 1; - values = list_create(); - values->auto_free = 1; - if (file_read_section(fd, "Globals", names, values) == 0) + g_memset(cfg_file, 0, sizeof(char) * 256); + /* default to port 3350 */ + g_strncpy(port, "3350", port_bytes - 1); + /* see if port is in xrdp.ini file */ + g_snprintf(cfg_file, 255, "%s/sesman.ini", XRDP_CFG_PATH); + fd = g_file_open(cfg_file); + + if (fd > 0) { - for (index = 0; index < names->count; index++) - { - val = (char*)list_get_item(names, index); - if (val != 0) - { - if (g_strcasecmp(val, "ListenPort") == 0) - { - val = (char*)list_get_item(values, index); - error = g_atoi(val); - if ((error > 0) && (error < 65000)) - { - g_strncpy(port, val, port_bytes - 1); - } - break; - } - } - } - } - list_delete(names); - list_delete(values); - g_file_close(fd); - } + names = list_create(); + names->auto_free = 1; + values = list_create(); + values->auto_free = 1; - return 0; + if (file_read_section(fd, "Globals", names, values) == 0) + { + for (index = 0; index < names->count; index++) + { + val = (char *)list_get_item(names, index); + + if (val != 0) + { + if (g_strcasecmp(val, "ListenPort") == 0) + { + val = (char *)list_get_item(values, index); + error = g_atoi(val); + + if ((error > 0) && (error < 65000)) + { + g_strncpy(port, val, port_bytes - 1); + } + + break; + } + } + } + } + + list_delete(names); + list_delete(values); + g_file_close(fd); + } + + return 0; } /*****************************************************************************/ /* returns error data coming from client that need to go to channel handler */ int APP_CC -xrdp_mm_process_channel_data(struct xrdp_mm* self, tbus param1, tbus param2, +xrdp_mm_process_channel_data(struct xrdp_mm *self, tbus param1, tbus param2, tbus param3, tbus param4) { - struct stream* s; - int rv; - int length; - int total_length; - int flags; - int id; - char* data; + struct stream *s; + int rv; + int length; + int total_length; + int flags; + int id; + char *data; - rv = 0; - if ((self->chan_trans != 0) && self->chan_trans_up) - { - s = trans_get_out_s(self->chan_trans, 8192); - if (s != 0) + rv = 0; + + if ((self->chan_trans != 0) && self->chan_trans_up) { - id = LOWORD(param1); - flags = HIWORD(param1); - length = param2; - data = (char*)param3; - total_length = param4; - if (total_length < length) - { - g_writeln("WARNING in xrdp_mm_process_channel_data(): total_len < length"); - total_length = length; - } - out_uint32_le(s, 0); /* version */ - out_uint32_le(s, 8 + 8 + 2 + 2 + 2 + 4 + length); - out_uint32_le(s, 5); /* msg id */ - out_uint32_le(s, 8 + 2 + 2 + 2 + 4 + length); - out_uint16_le(s, id); - out_uint16_le(s, flags); - out_uint16_le(s, length); - out_uint32_le(s, total_length); - out_uint8a(s, data, length); - s_mark_end(s); - rv = trans_force_write(self->chan_trans); - } - } + s = trans_get_out_s(self->chan_trans, 8192); - return rv; + if (s != 0) + { + id = LOWORD(param1); + flags = HIWORD(param1); + length = param2; + data = (char *)param3; + total_length = param4; + + if (total_length < length) + { + g_writeln("WARNING in xrdp_mm_process_channel_data(): total_len < length"); + total_length = length; + } + + out_uint32_le(s, 0); /* version */ + out_uint32_le(s, 8 + 8 + 2 + 2 + 2 + 4 + length); + out_uint32_le(s, 5); /* msg id */ + out_uint32_le(s, 8 + 2 + 2 + 2 + 4 + length); + out_uint16_le(s, id); + out_uint16_le(s, flags); + out_uint16_le(s, length); + out_uint32_le(s, total_length); + out_uint8a(s, data, length); + s_mark_end(s); + rv = trans_force_write(self->chan_trans); + } + } + + return rv; } /*****************************************************************************/ /* This is the callback registered for sesman communication replies. */ static int APP_CC -xrdp_mm_sesman_data_in(struct trans* trans) +xrdp_mm_sesman_data_in(struct trans *trans) { - struct xrdp_mm* self; - struct stream* s; - int version; - int size; - int error; - int code; + struct xrdp_mm *self; + struct stream *s; + int version; + int size; + int error; + int code; - if (trans == 0) - { - return 1; - } - self = (struct xrdp_mm*)(trans->callback_data); - s = trans_get_in_s(trans); - if (s == 0) - { - return 1; - } - in_uint32_be(s, version); - in_uint32_be(s, size); - error = trans_force_read(trans, size - 8); - if (error == 0) - { - in_uint16_be(s, code); - switch (code) + if (trans == 0) { - /* even when the request is denied the reply will hold 3 as the command. */ - case 3: - error = xrdp_mm_process_login_response(self, s); - break; - default: - xrdp_wm_log_msg(self->wm, "An undefined reply code was received from sesman"); - g_writeln("Fatal xrdp_mm_sesman_data_in: unknown cmd code %d", code); - cleanup_sesman_connection(self); - break; + return 1; } - } - return error; + self = (struct xrdp_mm *)(trans->callback_data); + s = trans_get_in_s(trans); + + if (s == 0) + { + return 1; + } + + in_uint32_be(s, version); + in_uint32_be(s, size); + error = trans_force_read(trans, size - 8); + + if (error == 0) + { + in_uint16_be(s, code); + + switch (code) + { + /* even when the request is denied the reply will hold 3 as the command. */ + case 3: + error = xrdp_mm_process_login_response(self, s); + break; + default: + xrdp_wm_log_msg(self->wm, "An undefined reply code was received from sesman"); + g_writeln("Fatal xrdp_mm_sesman_data_in: unknown cmd code %d", code); + cleanup_sesman_connection(self); + break; + } + } + + return error; } #ifdef ACCESS @@ -969,104 +1059,112 @@ xrdp_mm_sesman_data_in(struct trans* trans) /* return 0 on success */ int access_control(char *username, char *password, char *srv) { - int reply; - int rec = 1; // failure - struct stream* in_s; - struct stream* out_s; - unsigned long version; - unsigned short int dummy; - unsigned short int ok; - unsigned short int code; - unsigned long size; - int index; - int socket = g_tcp_socket(); - if (socket > 0) - { - /* we use a blocking socket here */ - reply = g_tcp_connect(socket, srv, "3350"); - if (reply == 0) - { - make_stream(in_s); - init_stream(in_s, 500); - make_stream(out_s); - init_stream(out_s, 500); - s_push_layer(out_s, channel_hdr, 8); - out_uint16_be(out_s, 4); /*0x04 means SCP_GW_AUTHENTICATION*/ - index = g_strlen(username); - out_uint16_be(out_s, index); - out_uint8a(out_s, username, index); + int reply; + int rec = 1; // failure + struct stream *in_s; + struct stream *out_s; + unsigned long version; + unsigned short int dummy; + unsigned short int ok; + unsigned short int code; + unsigned long size; + int index; + int socket = g_tcp_socket(); - index = g_strlen(password); - out_uint16_be(out_s, index); - out_uint8a(out_s, password, index); - s_mark_end(out_s); - s_pop_layer(out_s, channel_hdr); - out_uint32_be(out_s, 0); /* version */ - index = (int)(out_s->end - out_s->data); - out_uint32_be(out_s, index); /* size */ - /* g_writeln("Number of data to send : %d",index); */ - reply = g_tcp_send(socket, out_s->data, index, 0); - free_stream(out_s); - if (reply > 0) - { - /* We wait in 5 sec for a reply from sesman*/ - if (g_tcp_can_recv(socket, 5000)) + if (socket > 0) + { + /* we use a blocking socket here */ + reply = g_tcp_connect(socket, srv, "3350"); + + if (reply == 0) { - reply = g_tcp_recv(socket, in_s->end, 500, 0); - if (reply > 0) - { - in_s->end = in_s->end + reply; - in_uint32_be(in_s, version); - /*g_writeln("Version number in reply from sesman: %d",version) ; */ - in_uint32_be(in_s, size); - if ((size == 14) && (version == 0)) + make_stream(in_s); + init_stream(in_s, 500); + make_stream(out_s); + init_stream(out_s, 500); + s_push_layer(out_s, channel_hdr, 8); + out_uint16_be(out_s, 4); /*0x04 means SCP_GW_AUTHENTICATION*/ + index = g_strlen(username); + out_uint16_be(out_s, index); + out_uint8a(out_s, username, index); + + index = g_strlen(password); + out_uint16_be(out_s, index); + out_uint8a(out_s, password, index); + s_mark_end(out_s); + s_pop_layer(out_s, channel_hdr); + out_uint32_be(out_s, 0); /* version */ + index = (int)(out_s->end - out_s->data); + out_uint32_be(out_s, index); /* size */ + /* g_writeln("Number of data to send : %d",index); */ + reply = g_tcp_send(socket, out_s->data, index, 0); + free_stream(out_s); + + if (reply > 0) { - in_uint16_be(in_s, code); - in_uint16_be(in_s, ok); - in_uint16_be(in_s, dummy); - if (code != 4) - { - log_message(LOG_LEVEL_ERROR, "Returned cmd code from " - "sesman is corrupt"); - } - else - { - rec = ok; /* here we read the reply from the access control */ - } + /* We wait in 5 sec for a reply from sesman*/ + if (g_tcp_can_recv(socket, 5000)) + { + reply = g_tcp_recv(socket, in_s->end, 500, 0); + + if (reply > 0) + { + in_s->end = in_s->end + reply; + in_uint32_be(in_s, version); + /*g_writeln("Version number in reply from sesman: %d",version) ; */ + in_uint32_be(in_s, size); + + if ((size == 14) && (version == 0)) + { + in_uint16_be(in_s, code); + in_uint16_be(in_s, ok); + in_uint16_be(in_s, dummy); + + if (code != 4) + { + log_message(LOG_LEVEL_ERROR, "Returned cmd code from " + "sesman is corrupt"); + } + else + { + rec = ok; /* here we read the reply from the access control */ + } + } + else + { + log_message(LOG_LEVEL_ERROR, "Corrupt reply size or " + "version from sesman: %d", size); + } + } + else + { + log_message(LOG_LEVEL_ERROR, "No data received from sesman"); + } + } + else + { + log_message(LOG_LEVEL_ERROR, "Timeout when waiting for sesman"); + } } else { - log_message(LOG_LEVEL_ERROR, "Corrupt reply size or " - "version from sesman: %d", size); + log_message(LOG_LEVEL_ERROR, "No success sending to sesman"); } - } - else - { - log_message(LOG_LEVEL_ERROR, "No data received from sesman"); - } + + free_stream(in_s); + g_tcp_close(socket); } else { - log_message(LOG_LEVEL_ERROR, "Timeout when waiting for sesman"); + log_message(LOG_LEVEL_ERROR, "Failure connecting to socket sesman"); } - } - else - { - log_message(LOG_LEVEL_ERROR, "No success sending to sesman"); - } - free_stream(in_s); - g_tcp_close(socket); } else { - log_message(LOG_LEVEL_ERROR, "Failure connecting to socket sesman"); + log_message(LOG_LEVEL_ERROR, "Failure creating socket - for access control"); } - } - else - { - log_message(LOG_LEVEL_ERROR, "Failure creating socket - for access control"); - } - return rec; + + return rec; } #endif @@ -1074,1134 +1172,1244 @@ int access_control(char *username, char *password, char *srv) /* This routine clears all states to make sure that our next login will be * as expected. If the user does not press ok on the log window and try to * connect again we must make sure that no previous information is stored.*/ -void cleanup_states(struct xrdp_mm* self) +void cleanup_states(struct xrdp_mm *self) { - if (self != NULL) - { - self-> connected_state = 0; /* true if connected to sesman else false */ - self-> sesman_trans = NULL; /* connection to sesman */ - self-> sesman_trans_up = 0; /* true once connected to sesman */ - self-> delete_sesman_trans = 0; /* boolean set when done with sesman connection */ - self-> display = 0; /* 10 for :10.0, 11 for :11.0, etc */ - self-> code = 0; /* 0 Xvnc session 10 X11rdp session */ - self-> sesman_controlled = 0; /* true if this is a sesman session */ - self-> chan_trans = NULL; /* connection to chansrv */ - self-> chan_trans_up = 0; /* true once connected to chansrv */ - self-> delete_chan_trans = 0; /* boolean set when done with channel connection */ - self-> usechansrv = 0; /* true if chansrvport is set in xrdp.ini or using sesman */ - } + if (self != NULL) + { + self-> connected_state = 0; /* true if connected to sesman else false */ + self-> sesman_trans = NULL; /* connection to sesman */ + self-> sesman_trans_up = 0; /* true once connected to sesman */ + self-> delete_sesman_trans = 0; /* boolean set when done with sesman connection */ + self-> display = 0; /* 10 for :10.0, 11 for :11.0, etc */ + self-> code = 0; /* 0 Xvnc session 10 X11rdp session */ + self-> sesman_controlled = 0; /* true if this is a sesman session */ + self-> chan_trans = NULL; /* connection to chansrv */ + self-> chan_trans_up = 0; /* true once connected to chansrv */ + self-> delete_chan_trans = 0; /* boolean set when done with channel connection */ + self-> usechansrv = 0; /* true if chansrvport is set in xrdp.ini or using sesman */ + } } /*****************************************************************************/ int APP_CC -xrdp_mm_connect(struct xrdp_mm* self) +xrdp_mm_connect(struct xrdp_mm *self) { - struct list* names; - struct list* values; - int index; - int count; - int ok; - int rv; - char* name; - char* value; - char ip[256]; - char errstr[256]; - char text[256]; - char port[8]; - char chansrvport[256]; + struct list *names; + struct list *values; + int index; + int count; + int ok; + int rv; + char *name; + char *value; + char ip[256]; + char errstr[256]; + char text[256]; + char port[8]; + char chansrvport[256]; #ifdef ACCESS - int use_pam_auth = 0; - char pam_auth_sessionIP[256]; - char pam_auth_password[256]; - char pam_auth_username[256]; - char username[256]; - char password[256]; - username[0] = 0; - password[0] = 0; + int use_pam_auth = 0; + char pam_auth_sessionIP[256]; + char pam_auth_password[256]; + char pam_auth_username[256]; + char username[256]; + char password[256]; + username[0] = 0; + password[0] = 0; #endif - /* make sure we start in correct state */ - cleanup_states(self); - g_memset(ip, 0, sizeof(ip)); - g_memset(errstr, 0, sizeof(errstr)); - g_memset(text, 0, sizeof(text)); - g_memset(port, 0, sizeof(port)); - g_memset(chansrvport, 0, sizeof(chansrvport)); - rv = 0; /* success */ - names = self->login_names; - values = self->login_values; - count = names->count; - for (index = 0; index < count; index++) - { - name = (char*)list_get_item(names, index); - value = (char*)list_get_item(values, index); - if (g_strcasecmp(name, "ip") == 0) - { - g_strncpy(ip, value, 255); - } - else if (g_strcasecmp(name, "port") == 0) - { - if (g_strcasecmp(value, "-1") == 0) - { - self->sesman_controlled = 1; - } - } -#ifdef ACCESS - else if (g_strcasecmp(name, "pamusername") == 0) - { - use_pam_auth = 1; - g_strncpy(pam_auth_username, value, 255); - } - else if (g_strcasecmp(name, "pamsessionmng") == 0) - { - g_strncpy(pam_auth_sessionIP, value, 255); - } - else if (g_strcasecmp(name, "pampassword") == 0) - { - g_strncpy(pam_auth_password, value, 255); - } - else if (g_strcasecmp(name, "password") == 0) - { - g_strncpy(password, value, 255); - } - else if (g_strcasecmp(name, "username") == 0) - { - g_strncpy(username, value, 255); - } -#endif - else if (g_strcasecmp(name, "chansrvport") == 0) - { - g_strncpy(chansrvport, value, 255); - self->usechansrv = 1; - } - } -#ifdef ACCESS - if (use_pam_auth) - { - int reply; - char replytxt[80]; - char replymessage[4][80] = {"Ok","Sesman connect failure","User or password error","Privilege group error"}; - xrdp_wm_log_msg(self->wm, "Please wait, we now perform access control..."); - /* g_writeln("we use pam modules to check if we can approve this user"); */ - if (!g_strncmp(pam_auth_username, "same", 255)) - { - log_message(LOG_LEVEL_DEBUG, "pamusername copied from username - same: %s", username); - g_strncpy(pam_auth_username,username, 255); - } - if (!g_strncmp(pam_auth_password, "same", 255)) - { - log_message(LOG_LEVEL_DEBUG,"pam_auth_password copied from username - same: %s", password); - g_strncpy(pam_auth_password, password, 255); - } - /* access_control return 0 on success */ - reply = access_control(pam_auth_username, pam_auth_password, pam_auth_sessionIP); - if (reply >= 0 && reply < 4) - { - g_sprintf(replytxt,"Reply from access control: %s", replymessage[reply]); - } - else - { - g_sprintf(replytxt,"Reply from access control undefined"); - } - xrdp_wm_log_msg(self->wm,replytxt); - log_message(LOG_LEVEL_INFO,replytxt); - if (reply != 0) - { - rv = 1; - return rv; - } - } -#endif - if (self->sesman_controlled) - { - ok = 0; - trans_delete(self->sesman_trans); - self->sesman_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); - xrdp_mm_get_sesman_port(port, sizeof(port)); - g_snprintf(text, 255, "connecting to sesman ip %s port %s", ip, port); - xrdp_wm_log_msg(self->wm, text); - /* xrdp_mm_sesman_data_in is the callback that is called when data arrives */ - self->sesman_trans->trans_data_in = xrdp_mm_sesman_data_in; - self->sesman_trans->header_size = 8; - self->sesman_trans->callback_data = self; - /* try to connect up to 4 times */ - for (index = 0; index < 4; index++) - { - if (trans_connect(self->sesman_trans, ip, port, 3000) == 0) - { - self->sesman_trans_up = 1; - ok = 1; - break; - } - g_sleep(1000); - g_writeln("xrdp_mm_connect: connect failed " - "trying again..."); - } - if (ok) - { - /* fully connect */ - xrdp_wm_log_msg(self->wm, "sesman connect ok"); - self->connected_state = 1; - rv = xrdp_mm_send_login(self); - } - else - { - g_snprintf(errstr, 255, "Failure to connect to sesman: %s port: %s", - ip, port); - xrdp_wm_log_msg(self->wm, errstr); - trans_delete(self->sesman_trans); - self->sesman_trans = 0; - self->sesman_trans_up = 0; - rv = 1; - } - } - else /* no sesman */ - { - if (xrdp_mm_setup_mod1(self) == 0) - { - if (xrdp_mm_setup_mod2(self) == 0) - { - xrdp_wm_set_login_mode(self->wm, 10); - rv = 0; /*sucess*/ - } - else - { - /* connect error */ - g_snprintf(errstr, 255, "Failure to connect to: %s", ip); - xrdp_wm_log_msg(self->wm, errstr); - rv = 1; /* failure */ - } - } - else - { - g_writeln("Failure setting up module"); - } - if (self->wm->login_mode != 10) - { - xrdp_wm_set_login_mode(self->wm, 11); - xrdp_mm_module_cleanup(self); - rv = 1; /* failure */ - } - } + /* make sure we start in correct state */ + cleanup_states(self); + g_memset(ip, 0, sizeof(ip)); + g_memset(errstr, 0, sizeof(errstr)); + g_memset(text, 0, sizeof(text)); + g_memset(port, 0, sizeof(port)); + g_memset(chansrvport, 0, sizeof(chansrvport)); + rv = 0; /* success */ + names = self->login_names; + values = self->login_values; + count = names->count; - if ((self->wm->login_mode == 10) && (self->sesman_controlled == 0) && - (self->usechansrv != 0)) - { - /* if sesman controlled, this will connect later */ - xrdp_mm_connect_chansrv(self, "", chansrvport); - } - g_writeln("returnvalue from xrdp_mm_connect %d", rv); + for (index = 0; index < count; index++) + { + name = (char *)list_get_item(names, index); + value = (char *)list_get_item(values, index); - return rv; + if (g_strcasecmp(name, "ip") == 0) + { + g_strncpy(ip, value, 255); + } + else if (g_strcasecmp(name, "port") == 0) + { + if (g_strcasecmp(value, "-1") == 0) + { + self->sesman_controlled = 1; + } + } + +#ifdef ACCESS + else if (g_strcasecmp(name, "pamusername") == 0) + { + use_pam_auth = 1; + g_strncpy(pam_auth_username, value, 255); + } + else if (g_strcasecmp(name, "pamsessionmng") == 0) + { + g_strncpy(pam_auth_sessionIP, value, 255); + } + else if (g_strcasecmp(name, "pampassword") == 0) + { + g_strncpy(pam_auth_password, value, 255); + } + else if (g_strcasecmp(name, "password") == 0) + { + g_strncpy(password, value, 255); + } + else if (g_strcasecmp(name, "username") == 0) + { + g_strncpy(username, value, 255); + } + +#endif + else if (g_strcasecmp(name, "chansrvport") == 0) + { + g_strncpy(chansrvport, value, 255); + self->usechansrv = 1; + } + } + +#ifdef ACCESS + + if (use_pam_auth) + { + int reply; + char replytxt[80]; + char replymessage[4][80] = {"Ok", "Sesman connect failure", "User or password error", "Privilege group error"}; + xrdp_wm_log_msg(self->wm, "Please wait, we now perform access control..."); + + /* g_writeln("we use pam modules to check if we can approve this user"); */ + if (!g_strncmp(pam_auth_username, "same", 255)) + { + log_message(LOG_LEVEL_DEBUG, "pamusername copied from username - same: %s", username); + g_strncpy(pam_auth_username, username, 255); + } + + if (!g_strncmp(pam_auth_password, "same", 255)) + { + log_message(LOG_LEVEL_DEBUG, "pam_auth_password copied from username - same: %s", password); + g_strncpy(pam_auth_password, password, 255); + } + + /* access_control return 0 on success */ + reply = access_control(pam_auth_username, pam_auth_password, pam_auth_sessionIP); + + if (reply >= 0 && reply < 4) + { + g_sprintf(replytxt, "Reply from access control: %s", replymessage[reply]); + } + else + { + g_sprintf(replytxt, "Reply from access control undefined"); + } + + xrdp_wm_log_msg(self->wm, replytxt); + log_message(LOG_LEVEL_INFO, replytxt); + + if (reply != 0) + { + rv = 1; + return rv; + } + } + +#endif + + if (self->sesman_controlled) + { + ok = 0; + trans_delete(self->sesman_trans); + self->sesman_trans = trans_create(TRANS_MODE_TCP, 8192, 8192); + xrdp_mm_get_sesman_port(port, sizeof(port)); + g_snprintf(text, 255, "connecting to sesman ip %s port %s", ip, port); + xrdp_wm_log_msg(self->wm, text); + /* xrdp_mm_sesman_data_in is the callback that is called when data arrives */ + self->sesman_trans->trans_data_in = xrdp_mm_sesman_data_in; + self->sesman_trans->header_size = 8; + self->sesman_trans->callback_data = self; + + /* try to connect up to 4 times */ + for (index = 0; index < 4; index++) + { + if (trans_connect(self->sesman_trans, ip, port, 3000) == 0) + { + self->sesman_trans_up = 1; + ok = 1; + break; + } + + g_sleep(1000); + g_writeln("xrdp_mm_connect: connect failed " + "trying again..."); + } + + if (ok) + { + /* fully connect */ + xrdp_wm_log_msg(self->wm, "sesman connect ok"); + self->connected_state = 1; + rv = xrdp_mm_send_login(self); + } + else + { + g_snprintf(errstr, 255, "Failure to connect to sesman: %s port: %s", + ip, port); + xrdp_wm_log_msg(self->wm, errstr); + trans_delete(self->sesman_trans); + self->sesman_trans = 0; + self->sesman_trans_up = 0; + rv = 1; + } + } + else /* no sesman */ + { + if (xrdp_mm_setup_mod1(self) == 0) + { + if (xrdp_mm_setup_mod2(self) == 0) + { + xrdp_wm_set_login_mode(self->wm, 10); + rv = 0; /*sucess*/ + } + else + { + /* connect error */ + g_snprintf(errstr, 255, "Failure to connect to: %s", ip); + xrdp_wm_log_msg(self->wm, errstr); + rv = 1; /* failure */ + } + } + else + { + g_writeln("Failure setting up module"); + } + + if (self->wm->login_mode != 10) + { + xrdp_wm_set_login_mode(self->wm, 11); + xrdp_mm_module_cleanup(self); + rv = 1; /* failure */ + } + } + + if ((self->wm->login_mode == 10) && (self->sesman_controlled == 0) && + (self->usechansrv != 0)) + { + /* if sesman controlled, this will connect later */ + xrdp_mm_connect_chansrv(self, "", chansrvport); + } + + g_writeln("returnvalue from xrdp_mm_connect %d", rv); + + return rv; } /*****************************************************************************/ int APP_CC -xrdp_mm_get_wait_objs(struct xrdp_mm* self, - tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout) +xrdp_mm_get_wait_objs(struct xrdp_mm *self, + tbus *read_objs, int *rcount, + tbus *write_objs, int *wcount, int *timeout) { - int rv = 0; + int rv = 0; - if (self == 0) - { - return 0; - } - rv = 0; - if ((self->sesman_trans != 0) && self->sesman_trans_up) - { - trans_get_wait_objs(self->sesman_trans, read_objs, rcount); - } - if ((self->chan_trans != 0) && self->chan_trans_up) - { - trans_get_wait_objs(self->chan_trans, read_objs, rcount); - } - if (self->mod != 0) - { - if (self->mod->mod_get_wait_objs != 0) + if (self == 0) { - rv = self->mod->mod_get_wait_objs(self->mod, read_objs, rcount, - write_objs, wcount, timeout); + return 0; } - } - return rv; + rv = 0; + + if ((self->sesman_trans != 0) && self->sesman_trans_up) + { + trans_get_wait_objs(self->sesman_trans, read_objs, rcount); + } + + if ((self->chan_trans != 0) && self->chan_trans_up) + { + trans_get_wait_objs(self->chan_trans, read_objs, rcount); + } + + if (self->mod != 0) + { + if (self->mod->mod_get_wait_objs != 0) + { + rv = self->mod->mod_get_wait_objs(self->mod, read_objs, rcount, + write_objs, wcount, timeout); + } + } + + return rv; } /*****************************************************************************/ int APP_CC -xrdp_mm_check_wait_objs(struct xrdp_mm* self) +xrdp_mm_check_wait_objs(struct xrdp_mm *self) { - int rv; + int rv; - if (self == 0) - { - return 0; - } - rv = 0; - if ((self->sesman_trans != 0) && self->sesman_trans_up) - { - if (trans_check_wait_objs(self->sesman_trans) != 0) + if (self == 0) { - self->delete_sesman_trans = 1; + return 0; } - } - if ((self->chan_trans != 0) && self->chan_trans_up) - { - if (trans_check_wait_objs(self->chan_trans) != 0) - { - self->delete_chan_trans = 1; - } - } - if (self->mod != 0) - { - if (self->mod->mod_check_wait_objs != 0) - { - rv = self->mod->mod_check_wait_objs(self->mod); - } - } - if (self->delete_sesman_trans) - { - trans_delete(self->sesman_trans); - self->sesman_trans = 0; - self->sesman_trans_up = 0; - self->delete_sesman_trans = 0; - } - if (self->delete_chan_trans) - { - trans_delete(self->chan_trans); - self->chan_trans = 0; - self->chan_trans_up = 0; - self->delete_chan_trans = 0; - } - return rv; + rv = 0; + + if ((self->sesman_trans != 0) && self->sesman_trans_up) + { + if (trans_check_wait_objs(self->sesman_trans) != 0) + { + self->delete_sesman_trans = 1; + } + } + + if ((self->chan_trans != 0) && self->chan_trans_up) + { + if (trans_check_wait_objs(self->chan_trans) != 0) + { + self->delete_chan_trans = 1; + } + } + + if (self->mod != 0) + { + if (self->mod->mod_check_wait_objs != 0) + { + rv = self->mod->mod_check_wait_objs(self->mod); + } + } + + if (self->delete_sesman_trans) + { + trans_delete(self->sesman_trans); + self->sesman_trans = 0; + self->sesman_trans_up = 0; + self->delete_sesman_trans = 0; + } + + if (self->delete_chan_trans) + { + trans_delete(self->chan_trans); + self->chan_trans = 0; + self->chan_trans_up = 0; + self->delete_chan_trans = 0; + } + + return rv; } #if 0 /*****************************************************************************/ -struct xrdp_painter* APP_CC -get_painter(struct xrdp_mod* mod) +struct xrdp_painter *APP_CC +get_painter(struct xrdp_mod *mod) { - struct xrdp_wm* wm; - struct xrdp_painter* p; + struct xrdp_wm *wm; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { - wm = (struct xrdp_wm*)(mod->wm); - p = xrdp_painter_create(wm, wm->session); - mod->painter = (tintptr)p; - } - return p; + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + wm = (struct xrdp_wm *)(mod->wm); + p = xrdp_painter_create(wm, wm->session); + mod->painter = (tintptr)p; + } + + return p; } #endif /*****************************************************************************/ int DEFAULT_CC -server_begin_update(struct xrdp_mod* mod) +server_begin_update(struct xrdp_mod *mod) { - struct xrdp_wm* wm; - struct xrdp_painter* p; + struct xrdp_wm *wm; + struct xrdp_painter *p; - wm = (struct xrdp_wm*)(mod->wm); - p = xrdp_painter_create(wm, wm->session); - xrdp_painter_begin_update(p); - mod->painter = (long)p; - return 0; + wm = (struct xrdp_wm *)(mod->wm); + p = xrdp_painter_create(wm, wm->session); + xrdp_painter_begin_update(p); + mod->painter = (long)p; + return 0; } /*****************************************************************************/ int DEFAULT_CC -server_end_update(struct xrdp_mod* mod) +server_end_update(struct xrdp_mod *mod) { - struct xrdp_painter* p; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + xrdp_painter_end_update(p); + xrdp_painter_delete(p); + mod->painter = 0; return 0; - } - xrdp_painter_end_update(p); - xrdp_painter_delete(p); - mod->painter = 0; - return 0; } /*****************************************************************************/ /* got bell signal... try to send to client */ int DEFAULT_CC -server_bell_trigger(struct xrdp_mod* mod) +server_bell_trigger(struct xrdp_mod *mod) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - xrdp_wm_send_bell(wm); - return 0; -} - - -/*****************************************************************************/ -int DEFAULT_CC -server_fill_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy) -{ - struct xrdp_wm* wm; - struct xrdp_painter* p; - - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { + wm = (struct xrdp_wm *)(mod->wm); + xrdp_wm_send_bell(wm); + return 0; +} + + +/*****************************************************************************/ +int DEFAULT_CC +server_fill_rect(struct xrdp_mod *mod, int x, int y, int cx, int cy) +{ + struct xrdp_wm *wm; + struct xrdp_painter *p; + + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + wm = (struct xrdp_wm *)(mod->wm); + xrdp_painter_fill_rect(p, wm->target_surface, x, y, cx, cy); return 0; - } - wm = (struct xrdp_wm*)(mod->wm); - xrdp_painter_fill_rect(p, wm->target_surface, x, y, cx, cy); - return 0; } /*****************************************************************************/ int DEFAULT_CC -server_screen_blt(struct xrdp_mod* mod, int x, int y, int cx, int cy, +server_screen_blt(struct xrdp_mod *mod, int x, int y, int cx, int cy, int srcx, int srcy) { - struct xrdp_wm* wm; - struct xrdp_painter* p; + struct xrdp_wm *wm; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + wm = (struct xrdp_wm *)(mod->wm); + p->rop = 0xcc; + xrdp_painter_copy(p, wm->screen, wm->target_surface, x, y, cx, cy, srcx, srcy); return 0; - } - wm = (struct xrdp_wm*)(mod->wm); - p->rop = 0xcc; - xrdp_painter_copy(p, wm->screen, wm->target_surface, x, y, cx, cy, srcx, srcy); - return 0; } /*****************************************************************************/ int DEFAULT_CC -server_paint_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy, - char* data, int width, int height, int srcx, int srcy) +server_paint_rect(struct xrdp_mod *mod, int x, int y, int cx, int cy, + char *data, int width, int height, int srcx, int srcy) { - struct xrdp_wm* wm; - struct xrdp_bitmap* b; - struct xrdp_painter* p; + struct xrdp_wm *wm; + struct xrdp_bitmap *b; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + wm = (struct xrdp_wm *)(mod->wm); + b = xrdp_bitmap_create_with_data(width, height, wm->screen->bpp, data, wm); + xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy); + xrdp_bitmap_delete(b); return 0; - } - wm = (struct xrdp_wm*)(mod->wm); - b = xrdp_bitmap_create_with_data(width, height, wm->screen->bpp, data, wm); - xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy); - xrdp_bitmap_delete(b); - return 0; } /*****************************************************************************/ int DEFAULT_CC -server_set_pointer(struct xrdp_mod* mod, int x, int y, - char* data, char* mask) +server_set_pointer(struct xrdp_mod *mod, int x, int y, + char *data, char *mask) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - xrdp_wm_pointer(wm, data, mask, x, y); - return 0; -} - -/*****************************************************************************/ -int DEFAULT_CC -server_palette(struct xrdp_mod* mod, int* palette) -{ - struct xrdp_wm* wm; - - wm = (struct xrdp_wm*)(mod->wm); - if (g_memcmp(wm->palette, palette, 255 * sizeof(int)) != 0) - { - g_memcpy(wm->palette, palette, 256 * sizeof(int)); - xrdp_wm_send_palette(wm); - } - return 0; -} - -/*****************************************************************************/ -int DEFAULT_CC -server_msg(struct xrdp_mod* mod, char* msg, int code) -{ - struct xrdp_wm* wm; - - if (code == 1) - { - g_writeln(msg); + wm = (struct xrdp_wm *)(mod->wm); + xrdp_wm_pointer(wm, data, mask, x, y); return 0; - } - wm = (struct xrdp_wm*)(mod->wm); - return xrdp_wm_log_msg(wm, msg); } /*****************************************************************************/ int DEFAULT_CC -server_is_term(struct xrdp_mod* mod) +server_palette(struct xrdp_mod *mod, int *palette) { - return g_is_term(); -} + struct xrdp_wm *wm; -/*****************************************************************************/ -int DEFAULT_CC -server_set_clip(struct xrdp_mod* mod, int x, int y, int cx, int cy) -{ - struct xrdp_painter* p; + wm = (struct xrdp_wm *)(mod->wm); + + if (g_memcmp(wm->palette, palette, 255 * sizeof(int)) != 0) + { + g_memcpy(wm->palette, palette, 256 * sizeof(int)); + xrdp_wm_send_palette(wm); + } - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { return 0; - } - return xrdp_painter_set_clip(p, x, y, cx, cy); } /*****************************************************************************/ int DEFAULT_CC -server_reset_clip(struct xrdp_mod* mod) +server_msg(struct xrdp_mod *mod, char *msg, int code) { - struct xrdp_painter* p; + struct xrdp_wm *wm; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { - return 0; - } - return xrdp_painter_clr_clip(p); + if (code == 1) + { + g_writeln(msg); + return 0; + } + + wm = (struct xrdp_wm *)(mod->wm); + return xrdp_wm_log_msg(wm, msg); } /*****************************************************************************/ int DEFAULT_CC -server_set_fgcolor(struct xrdp_mod* mod, int fgcolor) +server_is_term(struct xrdp_mod *mod) { - struct xrdp_painter* p; - - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { - return 0; - } - p->fg_color = fgcolor; - p->pen.color = p->fg_color; - return 0; + return g_is_term(); } /*****************************************************************************/ int DEFAULT_CC -server_set_bgcolor(struct xrdp_mod* mod, int bgcolor) +server_set_clip(struct xrdp_mod *mod, int x, int y, int cx, int cy) { - struct xrdp_painter* p; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { - return 0; - } - p->bg_color = bgcolor; - return 0; + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + return xrdp_painter_set_clip(p, x, y, cx, cy); } /*****************************************************************************/ int DEFAULT_CC -server_set_opcode(struct xrdp_mod* mod, int opcode) +server_reset_clip(struct xrdp_mod *mod) { - struct xrdp_painter* p; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { - return 0; - } - p->rop = opcode; - return 0; + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + return xrdp_painter_clr_clip(p); } /*****************************************************************************/ int DEFAULT_CC -server_set_mixmode(struct xrdp_mod* mod, int mixmode) +server_set_fgcolor(struct xrdp_mod *mod, int fgcolor) { - struct xrdp_painter* p; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + p->fg_color = fgcolor; + p->pen.color = p->fg_color; return 0; - } - p->mix_mode = mixmode; - return 0; } /*****************************************************************************/ int DEFAULT_CC -server_set_brush(struct xrdp_mod* mod, int x_orgin, int y_orgin, - int style, char* pattern) +server_set_bgcolor(struct xrdp_mod *mod, int bgcolor) { - struct xrdp_painter* p; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + p->bg_color = bgcolor; return 0; - } - p->brush.x_orgin = x_orgin; - p->brush.y_orgin = y_orgin; - p->brush.style = style; - g_memcpy(p->brush.pattern, pattern, 8); - return 0; } /*****************************************************************************/ int DEFAULT_CC -server_set_pen(struct xrdp_mod* mod, int style, int width) +server_set_opcode(struct xrdp_mod *mod, int opcode) { - struct xrdp_painter* p; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + p->rop = opcode; return 0; - } - p->pen.style = style; - p->pen.width = width; - return 0; } /*****************************************************************************/ int DEFAULT_CC -server_draw_line(struct xrdp_mod* mod, int x1, int y1, int x2, int y2) +server_set_mixmode(struct xrdp_mod *mod, int mixmode) { - struct xrdp_wm* wm; - struct xrdp_painter* p; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + p->mix_mode = mixmode; return 0; - } - wm = (struct xrdp_wm*)(mod->wm); - return xrdp_painter_line(p, wm->target_surface, x1, y1, x2, y2); } /*****************************************************************************/ int DEFAULT_CC -server_add_char(struct xrdp_mod* mod, int font, int charactor, +server_set_brush(struct xrdp_mod *mod, int x_orgin, int y_orgin, + int style, char *pattern) +{ + struct xrdp_painter *p; + + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + p->brush.x_orgin = x_orgin; + p->brush.y_orgin = y_orgin; + p->brush.style = style; + g_memcpy(p->brush.pattern, pattern, 8); + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_set_pen(struct xrdp_mod *mod, int style, int width) +{ + struct xrdp_painter *p; + + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + p->pen.style = style; + p->pen.width = width; + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_draw_line(struct xrdp_mod *mod, int x1, int y1, int x2, int y2) +{ + struct xrdp_wm *wm; + struct xrdp_painter *p; + + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + wm = (struct xrdp_wm *)(mod->wm); + return xrdp_painter_line(p, wm->target_surface, x1, y1, x2, y2); +} + +/*****************************************************************************/ +int DEFAULT_CC +server_add_char(struct xrdp_mod *mod, int font, int charactor, int offset, int baseline, - int width, int height, char* data) + int width, int height, char *data) { - struct xrdp_font_char fi; + struct xrdp_font_char fi; - fi.offset = offset; - fi.baseline = baseline; - fi.width = width; - fi.height = height; - fi.incby = 0; - fi.data = data; - return libxrdp_orders_send_font(((struct xrdp_wm*)mod->wm)->session, - &fi, font, charactor); + fi.offset = offset; + fi.baseline = baseline; + fi.width = width; + fi.height = height; + fi.incby = 0; + fi.data = data; + return libxrdp_orders_send_font(((struct xrdp_wm *)mod->wm)->session, + &fi, font, charactor); } /*****************************************************************************/ int DEFAULT_CC -server_draw_text(struct xrdp_mod* mod, int font, +server_draw_text(struct xrdp_mod *mod, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, - int x, int y, char* data, int data_len) + int x, int y, char *data, int data_len) { - struct xrdp_wm* wm; - struct xrdp_painter* p; + struct xrdp_wm *wm; + struct xrdp_painter *p; - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { - return 0; - } - wm = (struct xrdp_wm*)(mod->wm); - return xrdp_painter_draw_text2(p, wm->target_surface, font, flags, - mixmode, clip_left, clip_top, - clip_right, clip_bottom, - box_left, box_top, - box_right, box_bottom, - x, y, data, data_len); + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + wm = (struct xrdp_wm *)(mod->wm); + return xrdp_painter_draw_text2(p, wm->target_surface, font, flags, + mixmode, clip_left, clip_top, + clip_right, clip_bottom, + box_left, box_top, + box_right, box_bottom, + x, y, data, data_len); } /*****************************************************************************/ int DEFAULT_CC -server_reset(struct xrdp_mod* mod, int width, int height, int bpp) +server_reset(struct xrdp_mod *mod, int width, int height, int bpp) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - if (wm->client_info == 0) - { - return 1; - } - /* older client can't resize */ - if (wm->client_info->build <= 419) - { + wm = (struct xrdp_wm *)(mod->wm); + + if (wm->client_info == 0) + { + return 1; + } + + /* older client can't resize */ + if (wm->client_info->build <= 419) + { + return 0; + } + + /* if same, don't need to do anything */ + if (wm->client_info->width == width && + wm->client_info->height == height && + wm->client_info->bpp == bpp) + { + return 0; + } + + /* reset lib, client_info gets updated in libxrdp_reset */ + if (libxrdp_reset(wm->session, width, height, bpp) != 0) + { + return 1; + } + + /* reset cache */ + xrdp_cache_reset(wm->cache, wm->client_info); + /* resize the main window */ + xrdp_bitmap_resize(wm->screen, wm->client_info->width, + wm->client_info->height); + /* load some stuff */ + xrdp_wm_load_static_colors_plus(wm, 0); + xrdp_wm_load_static_pointers(wm); return 0; - } - /* if same, don't need to do anything */ - if (wm->client_info->width == width && - wm->client_info->height == height && - wm->client_info->bpp == bpp) - { - return 0; - } - /* reset lib, client_info gets updated in libxrdp_reset */ - if (libxrdp_reset(wm->session, width, height, bpp) != 0) - { - return 1; - } - /* reset cache */ - xrdp_cache_reset(wm->cache, wm->client_info); - /* resize the main window */ - xrdp_bitmap_resize(wm->screen, wm->client_info->width, - wm->client_info->height); - /* load some stuff */ - xrdp_wm_load_static_colors_plus(wm, 0); - xrdp_wm_load_static_pointers(wm); - return 0; } /* read the channel section of the ini file into lists * return 1 on success 0 on failure */ -int read_allowed_channel_names(struct list* names, struct list* values) +int read_allowed_channel_names(struct list *names, struct list *values) { - int fd; - int ret = 0; - char cfg_file[256]; - int pos; - g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); - fd = g_file_open(cfg_file); - if (fd > 0) - { - names->auto_free = 1; - values->auto_free = 1; - pos = 0; - /* all values in this section can be valid channel names */ - if (file_read_section(fd, "channels", names, values) == 0) + int fd; + int ret = 0; + char cfg_file[256]; + int pos; + g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + fd = g_file_open(cfg_file); + + if (fd > 0) { - ret = 1; + names->auto_free = 1; + values->auto_free = 1; + pos = 0; + + /* all values in this section can be valid channel names */ + if (file_read_section(fd, "channels", names, values) == 0) + { + ret = 1; + } + else + { + g_writeln("Failure reading channel section of configuration"); + } + + g_file_close(fd); + return ret; } - else - { - g_writeln("Failure reading channel section of configuration"); - } - g_file_close(fd); - return ret; - } } /* internal function return 1 if name is in list of channels * and if the value is allowed */ int DEFAULT_CC -is_name_in_lists(char* inName, struct list* names, struct list* values) +is_name_in_lists(char *inName, struct list *names, struct list *values) { - int reply = 0; /*means not in the list*/ - int index; - char* val; - char* name; - for (index = 0; index < names->count; index++) - { - name = (char*)list_get_item(names, index); - if (name != 0) + int reply = 0; /*means not in the list*/ + int index; + char *val; + char *name; + + for (index = 0; index < names->count; index++) { - /* ex rdpdr ;rdpsnd ; drdynvc ; cliprdr */ - if (!g_strncmp(name, inName, MAX_CHANNEL_NAME)) - { - val = (char*)list_get_item(values, index); - if ((g_strcasecmp(val, "yes") == 0) || - (g_strcasecmp(val, "on") == 0) || - (g_strcasecmp(val, "true") == 0) || - (g_atoi(val) != 0)) + name = (char *)list_get_item(names, index); + + if (name != 0) { - reply = 1; + /* ex rdpdr ;rdpsnd ; drdynvc ; cliprdr */ + if (!g_strncmp(name, inName, MAX_CHANNEL_NAME)) + { + val = (char *)list_get_item(values, index); + + if ((g_strcasecmp(val, "yes") == 0) || + (g_strcasecmp(val, "on") == 0) || + (g_strcasecmp(val, "true") == 0) || + (g_atoi(val) != 0)) + { + reply = 1; + } + else + { + g_writeln("This channel is disabled: %s", name); + } + + break; /* stop loop - item found*/ + } } - else - { - g_writeln("This channel is disabled: %s", name); - } - break; /* stop loop - item found*/ - } } - } - return reply; + + return reply; } /* internal function only used once per session * creates the list of allowed channels and store the information * in wm struct */ -void init_channel_allowed(struct xrdp_wm* wm) +void init_channel_allowed(struct xrdp_wm *wm) { - int error; - int i; - char channelname[MAX_CHANNEL_NAME]; - int index = 0; - int allowindex = 0; - struct list* names; - struct list* values; - /* first reset allowedchannels */ - for (i = 0; i < MAX_NR_CHANNELS; i++) - { - /* 0 is a valid channel so we use -1 to mark the index as unused */ - wm->allowedchannels[i] = -1; - } - names = list_create(); - values = list_create(); - if (read_allowed_channel_names(names, values)) - { - do + int error; + int i; + char channelname[MAX_CHANNEL_NAME]; + int index = 0; + int allowindex = 0; + struct list *names; + struct list *values; + + /* first reset allowedchannels */ + for (i = 0; i < MAX_NR_CHANNELS; i++) { - /* libxrdp_query_channel return 1 on error*/ - error = libxrdp_query_channel(wm->session, index, channelname,NULL); - if (error == 0) - { - /* examples of channel names: rdpdr ; rdpsnd ; drdynvc ; cliprdr */ - if (is_name_in_lists(channelname, names, values)) + /* 0 is a valid channel so we use -1 to mark the index as unused */ + wm->allowedchannels[i] = -1; + } + + names = list_create(); + values = list_create(); + + if (read_allowed_channel_names(names, values)) + { + do { - g_writeln("The following channel is allowed: %s", channelname); - wm->allowedchannels[allowindex] = index; - allowindex++; - if (allowindex >= MAX_NR_CHANNELS) - { - g_writeln("Programming error in is_channel_allowed"); - error = 1; /* end loop */ - } + /* libxrdp_query_channel return 1 on error*/ + error = libxrdp_query_channel(wm->session, index, channelname, NULL); + + if (error == 0) + { + /* examples of channel names: rdpdr ; rdpsnd ; drdynvc ; cliprdr */ + if (is_name_in_lists(channelname, names, values)) + { + g_writeln("The following channel is allowed: %s", channelname); + wm->allowedchannels[allowindex] = index; + allowindex++; + + if (allowindex >= MAX_NR_CHANNELS) + { + g_writeln("Programming error in is_channel_allowed"); + error = 1; /* end loop */ + } + } + else + { + g_writeln("The following channel is not allowed: %s", channelname); + } + + index++; + } } - else - { - g_writeln("The following channel is not allowed: %s",channelname); - } - index++; - } - } while ((error == 0) && (index < MAX_NR_CHANNELS)); - } - else - { - g_writeln("Error reading channel section in inifile"); - } - list_delete(names); - list_delete(values); + while ((error == 0) && (index < MAX_NR_CHANNELS)); + } + else + { + g_writeln("Error reading channel section in inifile"); + } + + list_delete(names); + list_delete(values); } /*****************************************************************************/ /* This function returns 1 if the channelID is allowed by rule set * returns 0 if not allowed */ -int DEFAULT_CC is_channel_allowed(struct xrdp_wm* wm, int channel_id) +int DEFAULT_CC is_channel_allowed(struct xrdp_wm *wm, int channel_id) { - int i; - int reply = 0; /* not allowed */ - /* The first time each client is using this function we have to - * define the list of allowed channels */ - if (wm->allowedinitialized == 0) - { - init_channel_allowed(wm); - g_writeln("allow channel list initialized"); - wm->allowedinitialized = 1; - } - for(i = 0; i < MAX_NR_CHANNELS; i++) - { - if (channel_id == wm->allowedchannels[i]) + int i; + int reply = 0; /* not allowed */ + + /* The first time each client is using this function we have to + * define the list of allowed channels */ + if (wm->allowedinitialized == 0) { - /*g_writeln("Channel allowed: %d",channel_id);*/ - reply = 1; /*channel allowed*/ - break; + init_channel_allowed(wm); + g_writeln("allow channel list initialized"); + wm->allowedinitialized = 1; } - else if (wm->allowedchannels[i] == -1) + + for (i = 0; i < MAX_NR_CHANNELS; i++) { - /* We are in the unused space of the allowedchannels list - * We can end the loop */ - break; + if (channel_id == wm->allowedchannels[i]) + { + /*g_writeln("Channel allowed: %d",channel_id);*/ + reply = 1; /*channel allowed*/ + break; + } + else if (wm->allowedchannels[i] == -1) + { + /* We are in the unused space of the allowedchannels list + * We can end the loop */ + break; + } } - } - /*if (reply == 0) - { - g_writeln("This channel is NOT allowed: %d",channel_id) ; - }*/ - return reply; + + /*if (reply == 0) + { + g_writeln("This channel is NOT allowed: %d",channel_id) ; + }*/ + return reply; } /*****************************************************************************/ /*return 0 if the index is not found*/ int DEFAULT_CC -server_query_channel(struct xrdp_mod* mod, int index, char* channel_name, - int* channel_flags) +server_query_channel(struct xrdp_mod *mod, int index, char *channel_name, + int *channel_flags) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - if (wm->mm->usechansrv) - { - return 1; - } - return libxrdp_query_channel(wm->session, index, channel_name, - channel_flags); + wm = (struct xrdp_wm *)(mod->wm); + + if (wm->mm->usechansrv) + { + return 1; + } + + return libxrdp_query_channel(wm->session, index, channel_name, + channel_flags); } /*****************************************************************************/ /* returns -1 on error */ int DEFAULT_CC -server_get_channel_id(struct xrdp_mod* mod, char* name) +server_get_channel_id(struct xrdp_mod *mod, char *name) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - if (wm->mm->usechansrv) - { - return -1; - } - return libxrdp_get_channel_id(wm->session, name); -} + wm = (struct xrdp_wm *)(mod->wm); -/*****************************************************************************/ -int DEFAULT_CC -server_send_to_channel(struct xrdp_mod* mod, int channel_id, - char* data, int data_len, - int total_data_len, int flags) -{ - struct xrdp_wm* wm; - - wm = (struct xrdp_wm*)(mod->wm); - if (is_channel_allowed(wm, channel_id)) - { if (wm->mm->usechansrv) { - return 1; + return -1; } - return libxrdp_send_to_channel(wm->session, channel_id, data, data_len, - total_data_len, flags); - } - else - { - return 1; - } + + return libxrdp_get_channel_id(wm->session, name); } /*****************************************************************************/ int DEFAULT_CC -server_create_os_surface(struct xrdp_mod* mod, int rdpindex, - int width, int height) +server_send_to_channel(struct xrdp_mod *mod, int channel_id, + char *data, int data_len, + int total_data_len, int flags) { - struct xrdp_wm* wm; - struct xrdp_bitmap* bitmap; - int error; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - bitmap = xrdp_bitmap_create(width, height, wm->screen->bpp, - WND_TYPE_OFFSCREEN, wm); - error = xrdp_cache_add_os_bitmap(wm->cache, bitmap, rdpindex); - if (error != 0) - { - g_writeln("server_create_os_surface: xrdp_cache_add_os_bitmap failed"); - return 1; - } - bitmap->item_index = rdpindex; - bitmap->id = rdpindex; - return 0; -} + wm = (struct xrdp_wm *)(mod->wm); -/*****************************************************************************/ -int DEFAULT_CC -server_switch_os_surface(struct xrdp_mod* mod, int rdpindex) -{ - struct xrdp_wm* wm; - struct xrdp_os_bitmap_item* bi; - struct xrdp_painter* p; - - //g_writeln("server_switch_os_surface: id 0x%x", id); - wm = (struct xrdp_wm*)(mod->wm); - if (rdpindex == -1) - { - //g_writeln("server_switch_os_surface: setting target_surface to screen"); - wm->target_surface = wm->screen; - p = (struct xrdp_painter*)(mod->painter); - if (p != 0) + if (is_channel_allowed(wm, channel_id)) { - //g_writeln("setting target"); - wm_painter_set_target(p); - } - return 0; - } - bi = xrdp_cache_get_os_bitmap(wm->cache, rdpindex); - if (bi != 0) - { - //g_writeln("server_switch_os_surface: setting target_surface to rdpid %d", id); - wm->target_surface = bi->bitmap; - p = (struct xrdp_painter*)(mod->painter); - if (p != 0) - { - //g_writeln("setting target"); - wm_painter_set_target(p); - } - } - else - { - g_writeln("server_switch_os_surface: error finding id %d", rdpindex); - } - return 0; -} + if (wm->mm->usechansrv) + { + return 1; + } -/*****************************************************************************/ -int DEFAULT_CC -server_delete_os_surface(struct xrdp_mod* mod, int rdpindex) -{ - struct xrdp_wm* wm; - struct xrdp_painter* p; - - //g_writeln("server_delete_os_surface: id 0x%x", id); - wm = (struct xrdp_wm*)(mod->wm); - if (wm->target_surface->type == WND_TYPE_OFFSCREEN) - { - if (wm->target_surface->id == rdpindex) - { - g_writeln("server_delete_os_surface: setting target_surface to screen"); - wm->target_surface = wm->screen; - p = (struct xrdp_painter*)(mod->painter); - if (p != 0) - { - //g_writeln("setting target"); - wm_painter_set_target(p); - } - } - } - xrdp_cache_remove_os_bitmap(wm->cache, rdpindex); - return 0; -} - -/*****************************************************************************/ -int DEFAULT_CC -server_paint_rect_os(struct xrdp_mod* mod, int x, int y, int cx, int cy, - int rdpindex, int srcx, int srcy) -{ - struct xrdp_wm* wm; - struct xrdp_bitmap* b; - struct xrdp_painter* p; - struct xrdp_os_bitmap_item* bi; - - p = (struct xrdp_painter*)(mod->painter); - if (p == 0) - { - return 0; - } - wm = (struct xrdp_wm*)(mod->wm); - bi = xrdp_cache_get_os_bitmap(wm->cache, rdpindex); - if (bi != 0) - { - b = bi->bitmap; - xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy); - } - else - { - g_writeln("server_paint_rect_os: error finding id %d", rdpindex); - } - return 0; -} - -/*****************************************************************************/ -int DEFAULT_CC -server_set_hints(struct xrdp_mod* mod, int hints, int mask) -{ - struct xrdp_wm* wm; - - wm = (struct xrdp_wm*)(mod->wm); - if (mask & 1) - { - if (hints & 1) - { - wm->hints |= 1; + return libxrdp_send_to_channel(wm->session, channel_id, data, data_len, + total_data_len, flags); } else { - wm->hints &= ~1; + return 1; } - } - return 0; } /*****************************************************************************/ int DEFAULT_CC -server_window_new_update(struct xrdp_mod* mod, int window_id, - struct rail_window_state_order* window_state, +server_create_os_surface(struct xrdp_mod *mod, int rdpindex, + int width, int height) +{ + struct xrdp_wm *wm; + struct xrdp_bitmap *bitmap; + int error; + + wm = (struct xrdp_wm *)(mod->wm); + bitmap = xrdp_bitmap_create(width, height, wm->screen->bpp, + WND_TYPE_OFFSCREEN, wm); + error = xrdp_cache_add_os_bitmap(wm->cache, bitmap, rdpindex); + + if (error != 0) + { + g_writeln("server_create_os_surface: xrdp_cache_add_os_bitmap failed"); + return 1; + } + + bitmap->item_index = rdpindex; + bitmap->id = rdpindex; + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_switch_os_surface(struct xrdp_mod *mod, int rdpindex) +{ + struct xrdp_wm *wm; + struct xrdp_os_bitmap_item *bi; + struct xrdp_painter *p; + + //g_writeln("server_switch_os_surface: id 0x%x", id); + wm = (struct xrdp_wm *)(mod->wm); + + if (rdpindex == -1) + { + //g_writeln("server_switch_os_surface: setting target_surface to screen"); + wm->target_surface = wm->screen; + p = (struct xrdp_painter *)(mod->painter); + + if (p != 0) + { + //g_writeln("setting target"); + wm_painter_set_target(p); + } + + return 0; + } + + bi = xrdp_cache_get_os_bitmap(wm->cache, rdpindex); + + if (bi != 0) + { + //g_writeln("server_switch_os_surface: setting target_surface to rdpid %d", id); + wm->target_surface = bi->bitmap; + p = (struct xrdp_painter *)(mod->painter); + + if (p != 0) + { + //g_writeln("setting target"); + wm_painter_set_target(p); + } + } + else + { + g_writeln("server_switch_os_surface: error finding id %d", rdpindex); + } + + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_delete_os_surface(struct xrdp_mod *mod, int rdpindex) +{ + struct xrdp_wm *wm; + struct xrdp_painter *p; + + //g_writeln("server_delete_os_surface: id 0x%x", id); + wm = (struct xrdp_wm *)(mod->wm); + + if (wm->target_surface->type == WND_TYPE_OFFSCREEN) + { + if (wm->target_surface->id == rdpindex) + { + g_writeln("server_delete_os_surface: setting target_surface to screen"); + wm->target_surface = wm->screen; + p = (struct xrdp_painter *)(mod->painter); + + if (p != 0) + { + //g_writeln("setting target"); + wm_painter_set_target(p); + } + } + } + + xrdp_cache_remove_os_bitmap(wm->cache, rdpindex); + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_paint_rect_os(struct xrdp_mod *mod, int x, int y, int cx, int cy, + int rdpindex, int srcx, int srcy) +{ + struct xrdp_wm *wm; + struct xrdp_bitmap *b; + struct xrdp_painter *p; + struct xrdp_os_bitmap_item *bi; + + p = (struct xrdp_painter *)(mod->painter); + + if (p == 0) + { + return 0; + } + + wm = (struct xrdp_wm *)(mod->wm); + bi = xrdp_cache_get_os_bitmap(wm->cache, rdpindex); + + if (bi != 0) + { + b = bi->bitmap; + xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy); + } + else + { + g_writeln("server_paint_rect_os: error finding id %d", rdpindex); + } + + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_set_hints(struct xrdp_mod *mod, int hints, int mask) +{ + struct xrdp_wm *wm; + + wm = (struct xrdp_wm *)(mod->wm); + + if (mask & 1) + { + if (hints & 1) + { + wm->hints |= 1; + } + else + { + wm->hints &= ~1; + } + } + + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_window_new_update(struct xrdp_mod *mod, int window_id, + struct rail_window_state_order *window_state, int flags) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - return libxrdp_window_new_update(wm->session, window_id, - window_state, flags); + wm = (struct xrdp_wm *)(mod->wm); + return libxrdp_window_new_update(wm->session, window_id, + window_state, flags); } /*****************************************************************************/ int DEFAULT_CC -server_window_delete(struct xrdp_mod* mod, int window_id) +server_window_delete(struct xrdp_mod *mod, int window_id) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - return libxrdp_window_delete(wm->session, window_id); + wm = (struct xrdp_wm *)(mod->wm); + return libxrdp_window_delete(wm->session, window_id); } /*****************************************************************************/ int DEFAULT_CC -server_window_icon(struct xrdp_mod* mod, int window_id, int cache_entry, - int cache_id, struct rail_icon_info* icon_info, +server_window_icon(struct xrdp_mod *mod, int window_id, int cache_entry, + int cache_id, struct rail_icon_info *icon_info, int flags) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - return libxrdp_window_icon(wm->session, window_id, cache_entry, cache_id, - icon_info, flags); + wm = (struct xrdp_wm *)(mod->wm); + return libxrdp_window_icon(wm->session, window_id, cache_entry, cache_id, + icon_info, flags); } /*****************************************************************************/ int DEFAULT_CC -server_window_cached_icon(struct xrdp_mod* mod, +server_window_cached_icon(struct xrdp_mod *mod, int window_id, int cache_entry, int cache_id, int flags) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - return libxrdp_window_cached_icon(wm->session, window_id, cache_entry, - cache_id, flags); + wm = (struct xrdp_wm *)(mod->wm); + return libxrdp_window_cached_icon(wm->session, window_id, cache_entry, + cache_id, flags); } /*****************************************************************************/ int DEFAULT_CC -server_notify_new_update(struct xrdp_mod* mod, +server_notify_new_update(struct xrdp_mod *mod, int window_id, int notify_id, - struct rail_notify_state_order* notify_state, + struct rail_notify_state_order *notify_state, int flags) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - return libxrdp_notify_new_update(wm->session, window_id, notify_id, - notify_state, flags); + wm = (struct xrdp_wm *)(mod->wm); + return libxrdp_notify_new_update(wm->session, window_id, notify_id, + notify_state, flags); } /*****************************************************************************/ int DEFAULT_CC -server_notify_delete(struct xrdp_mod* mod, int window_id, +server_notify_delete(struct xrdp_mod *mod, int window_id, int notify_id) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - return libxrdp_notify_delete(wm->session, window_id, notify_id); + wm = (struct xrdp_wm *)(mod->wm); + return libxrdp_notify_delete(wm->session, window_id, notify_id); } /*****************************************************************************/ int DEFAULT_CC -server_monitored_desktop(struct xrdp_mod* mod, - struct rail_monitored_desktop_order* mdo, +server_monitored_desktop(struct xrdp_mod *mod, + struct rail_monitored_desktop_order *mdo, int flags) { - struct xrdp_wm* wm; + struct xrdp_wm *wm; - wm = (struct xrdp_wm*)(mod->wm); - return libxrdp_monitored_desktop(wm->session, mdo, flags); + wm = (struct xrdp_wm *)(mod->wm); + return libxrdp_monitored_desktop(wm->session, mdo, flags); } diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c index b91be16d..0b867089 100644 --- a/xrdp/xrdp_painter.c +++ b/xrdp/xrdp_painter.c @@ -1,205 +1,218 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2012 - - painter, gc - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * painter, gc + */ #include "xrdp.h" /*****************************************************************************/ -struct xrdp_painter* APP_CC -xrdp_painter_create(struct xrdp_wm* wm, struct xrdp_session* session) +struct xrdp_painter *APP_CC +xrdp_painter_create(struct xrdp_wm *wm, struct xrdp_session *session) { - struct xrdp_painter* self; + struct xrdp_painter *self; - self = (struct xrdp_painter*)g_malloc(sizeof(struct xrdp_painter), 1); - self->wm = wm; - self->session = session; - self->rop = 0xcc; /* copy gota use 0xcc*/ - self->clip_children = 1; - return self; + self = (struct xrdp_painter *)g_malloc(sizeof(struct xrdp_painter), 1); + self->wm = wm; + self->session = session; + self->rop = 0xcc; /* copy gota use 0xcc*/ + self->clip_children = 1; + return self; } /*****************************************************************************/ void APP_CC -xrdp_painter_delete(struct xrdp_painter* self) +xrdp_painter_delete(struct xrdp_painter *self) { - if (self == 0) - { - return; - } - g_free(self); -} - -/*****************************************************************************/ -int APP_CC -wm_painter_set_target(struct xrdp_painter* self) -{ - int surface_index; - int index; - struct list* del_list; - - if (self->wm->target_surface->type == WND_TYPE_SCREEN) - { - if (self->wm->current_surface_index != 0xffff) + if (self == 0) { - libxrdp_orders_send_switch_os_surface(self->session, 0xffff); - self->wm->current_surface_index = 0xffff; + return; } - } - else if (self->wm->target_surface->type == WND_TYPE_OFFSCREEN) - { - surface_index = self->wm->target_surface->item_index; - if (surface_index != self->wm->current_surface_index) + + g_free(self); +} + +/*****************************************************************************/ +int APP_CC +wm_painter_set_target(struct xrdp_painter *self) +{ + int surface_index; + int index; + struct list *del_list; + + if (self->wm->target_surface->type == WND_TYPE_SCREEN) { - if (self->wm->target_surface->tab_stop == 0) /* tab_stop is hack */ - { - del_list = self->wm->cache->xrdp_os_del_list; - index = list_index_of(del_list, surface_index); - list_remove_item(del_list, index); - libxrdp_orders_send_create_os_surface(self->session, surface_index, - self->wm->target_surface->width, - self->wm->target_surface->height, - del_list); - self->wm->target_surface->tab_stop = 1; - list_clear(del_list); - } - libxrdp_orders_send_switch_os_surface(self->session, surface_index); - self->wm->current_surface_index = surface_index; + if (self->wm->current_surface_index != 0xffff) + { + libxrdp_orders_send_switch_os_surface(self->session, 0xffff); + self->wm->current_surface_index = 0xffff; + } + } + else if (self->wm->target_surface->type == WND_TYPE_OFFSCREEN) + { + surface_index = self->wm->target_surface->item_index; + + if (surface_index != self->wm->current_surface_index) + { + if (self->wm->target_surface->tab_stop == 0) /* tab_stop is hack */ + { + del_list = self->wm->cache->xrdp_os_del_list; + index = list_index_of(del_list, surface_index); + list_remove_item(del_list, index); + libxrdp_orders_send_create_os_surface(self->session, surface_index, + self->wm->target_surface->width, + self->wm->target_surface->height, + del_list); + self->wm->target_surface->tab_stop = 1; + list_clear(del_list); + } + + libxrdp_orders_send_switch_os_surface(self->session, surface_index); + self->wm->current_surface_index = surface_index; + } + } + else + { + g_writeln("xrdp_painter_begin_update: bad target_surface"); } - } - else - { - g_writeln("xrdp_painter_begin_update: bad target_surface"); - } - return 0; -} -/*****************************************************************************/ -int APP_CC -xrdp_painter_begin_update(struct xrdp_painter* self) -{ - if (self == 0) - { return 0; - } - libxrdp_orders_init(self->session); - wm_painter_set_target(self); - return 0; } /*****************************************************************************/ int APP_CC -xrdp_painter_end_update(struct xrdp_painter* self) +xrdp_painter_begin_update(struct xrdp_painter *self) { - if (self == 0) - { + if (self == 0) + { + return 0; + } + + libxrdp_orders_init(self->session); + wm_painter_set_target(self); return 0; - } - libxrdp_orders_send(self->session); - return 0; } /*****************************************************************************/ int APP_CC -xrdp_painter_font_needed(struct xrdp_painter* self) +xrdp_painter_end_update(struct xrdp_painter *self) { - if (self->font == 0) - { - self->font = self->wm->default_font; - } - return 0; + if (self == 0) + { + return 0; + } + + libxrdp_orders_send(self->session); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_painter_font_needed(struct xrdp_painter *self) +{ + if (self->font == 0) + { + self->font = self->wm->default_font; + } + + return 0; } #if 0 /*****************************************************************************/ /* returns boolean, true if there is something to draw */ static int APP_CC -xrdp_painter_clip_adj(struct xrdp_painter* self, int* x, int* y, - int* cx, int* cy) +xrdp_painter_clip_adj(struct xrdp_painter *self, int *x, int *y, + int *cx, int *cy) { - int dx; - int dy; + int dx; + int dy; - if (!self->use_clip) - { + if (!self->use_clip) + { + return 1; + } + + if (self->clip.left > *x) + { + dx = self->clip.left - *x; + } + else + { + dx = 0; + } + + if (self->clip.top > *y) + { + dy = self->clip.top - *y; + } + else + { + dy = 0; + } + + if (*x + *cx > self->clip.right) + { + *cx = *cx - ((*x + *cx) - self->clip.right); + } + + if (*y + *cy > self->clip.bottom) + { + *cy = *cy - ((*y + *cy) - self->clip.bottom); + } + + *cx = *cx - dx; + *cy = *cy - dy; + + if (*cx <= 0) + { + return 0; + } + + if (*cy <= 0) + { + return 0; + } + + *x = *x + dx; + *y = *y + dy; return 1; - } - if (self->clip.left > *x) - { - dx = self->clip.left - *x; - } - else - { - dx = 0; - } - if (self->clip.top > *y) - { - dy = self->clip.top - *y; - } - else - { - dy = 0; - } - if (*x + *cx > self->clip.right) - { - *cx = *cx - ((*x + *cx) - self->clip.right); - } - if (*y + *cy > self->clip.bottom) - { - *cy = *cy - ((*y + *cy) - self->clip.bottom); - } - *cx = *cx - dx; - *cy = *cy - dy; - if (*cx <= 0) - { - return 0; - } - if (*cy <= 0) - { - return 0; - } - *x = *x + dx; - *y = *y + dy; - return 1; } #endif /*****************************************************************************/ int APP_CC -xrdp_painter_set_clip(struct xrdp_painter* self, +xrdp_painter_set_clip(struct xrdp_painter *self, int x, int y, int cx, int cy) { - self->use_clip = &self->clip; - self->clip.left = x; - self->clip.top = y; - self->clip.right = x + cx; - self->clip.bottom = y + cy; - return 0; + self->use_clip = &self->clip; + self->clip.left = x; + self->clip.top = y; + self->clip.right = x + cx; + self->clip.bottom = y + cy; + return 0; } /*****************************************************************************/ int APP_CC -xrdp_painter_clr_clip(struct xrdp_painter* self) +xrdp_painter_clr_clip(struct xrdp_painter *self) { - self->use_clip = 0; - return 0; + self->use_clip = 0; + return 0; } #if 0 @@ -207,631 +220,720 @@ xrdp_painter_clr_clip(struct xrdp_painter* self) static int APP_CC xrdp_painter_rop(int rop, int src, int dst) { - switch (rop & 0x0f) - { - case 0x0: return 0; - case 0x1: return ~(src | dst); - case 0x2: return (~src) & dst; - case 0x3: return ~src; - case 0x4: return src & (~dst); - case 0x5: return ~(dst); - case 0x6: return src ^ dst; - case 0x7: return ~(src & dst); - case 0x8: return src & dst; - case 0x9: return ~(src) ^ dst; - case 0xa: return dst; - case 0xb: return (~src) | dst; - case 0xc: return src; - case 0xd: return src | (~dst); - case 0xe: return src | dst; - case 0xf: return ~0; - } - return dst; + switch (rop & 0x0f) + { + case 0x0: + return 0; + case 0x1: + return ~(src | dst); + case 0x2: + return (~src) & dst; + case 0x3: + return ~src; + case 0x4: + return src & (~dst); + case 0x5: + return ~(dst); + case 0x6: + return src ^ dst; + case 0x7: + return ~(src & dst); + case 0x8: + return src & dst; + case 0x9: + return ~(src) ^ dst; + case 0xa: + return dst; + case 0xb: + return (~src) | dst; + case 0xc: + return src; + case 0xd: + return src | (~dst); + case 0xe: + return src | dst; + case 0xf: + return ~0; + } + + return dst; } #endif /*****************************************************************************/ int APP_CC -xrdp_painter_text_width(struct xrdp_painter* self, char* text) +xrdp_painter_text_width(struct xrdp_painter *self, char *text) { - int index; - int rv; - int len; - struct xrdp_font_char* font_item; - twchar* wstr; + int index; + int rv; + int len; + struct xrdp_font_char *font_item; + twchar *wstr; - xrdp_painter_font_needed(self); - if (self->font == 0) - { - return 0; - } - if (text == 0) - { - return 0; - } - rv = 0; - len = g_mbstowcs(0, text, 0); - wstr = (twchar*)g_malloc((len + 2) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); - for (index = 0; index < len; index++) - { - font_item = self->font->font_items + wstr[index]; - rv = rv + font_item->incby; - } - g_free(wstr); - return rv; + xrdp_painter_font_needed(self); + + if (self->font == 0) + { + return 0; + } + + if (text == 0) + { + return 0; + } + + rv = 0; + len = g_mbstowcs(0, text, 0); + wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0); + g_mbstowcs(wstr, text, len + 1); + + for (index = 0; index < len; index++) + { + font_item = self->font->font_items + wstr[index]; + rv = rv + font_item->incby; + } + + g_free(wstr); + return rv; } /*****************************************************************************/ int APP_CC -xrdp_painter_text_height(struct xrdp_painter* self, char* text) +xrdp_painter_text_height(struct xrdp_painter *self, char *text) { - int index; - int rv; - int len; - struct xrdp_font_char* font_item; - twchar* wstr; + int index; + int rv; + int len; + struct xrdp_font_char *font_item; + twchar *wstr; - xrdp_painter_font_needed(self); - if (self->font == 0) - { - return 0; - } - if (text == 0) - { - return 0; - } - rv = 0; - len = g_mbstowcs(0, text, 0); - wstr = (twchar*)g_malloc((len + 2) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); - for (index = 0; index < len; index++) - { - font_item = self->font->font_items + wstr[index]; - rv = MAX(rv, font_item->height); - } - g_free(wstr); - return rv; + xrdp_painter_font_needed(self); + + if (self->font == 0) + { + return 0; + } + + if (text == 0) + { + return 0; + } + + rv = 0; + len = g_mbstowcs(0, text, 0); + wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0); + g_mbstowcs(wstr, text, len + 1); + + for (index = 0; index < len; index++) + { + font_item = self->font->font_items + wstr[index]; + rv = MAX(rv, font_item->height); + } + + g_free(wstr); + return rv; } /*****************************************************************************/ static int APP_CC -xrdp_painter_setup_brush(struct xrdp_painter* self, - struct xrdp_brush* out_brush, - struct xrdp_brush* in_brush) +xrdp_painter_setup_brush(struct xrdp_painter *self, + struct xrdp_brush *out_brush, + struct xrdp_brush *in_brush) { - int cache_id; + int cache_id; - g_memcpy(out_brush, in_brush, sizeof(struct xrdp_brush)); - if (in_brush->style == 3) - { - if (self->session->client_info->brush_cache_code == 1) + g_memcpy(out_brush, in_brush, sizeof(struct xrdp_brush)); + + if (in_brush->style == 3) { - cache_id = xrdp_cache_add_brush(self->wm->cache, in_brush->pattern); - g_memset(out_brush->pattern, 0, 8); - out_brush->pattern[0] = cache_id; - out_brush->style = 0x81; + if (self->session->client_info->brush_cache_code == 1) + { + cache_id = xrdp_cache_add_brush(self->wm->cache, in_brush->pattern); + g_memset(out_brush->pattern, 0, 8); + out_brush->pattern[0] = cache_id; + out_brush->style = 0x81; + } } - } - return 0; + + return 0; } /*****************************************************************************/ /* fill in an area of the screen with one color */ int APP_CC -xrdp_painter_fill_rect(struct xrdp_painter* self, - struct xrdp_bitmap* dst, +xrdp_painter_fill_rect(struct xrdp_painter *self, + struct xrdp_bitmap *dst, int x, int y, int cx, int cy) { - struct xrdp_rect clip_rect; - struct xrdp_rect draw_rect; - struct xrdp_rect rect; - struct xrdp_region* region; - struct xrdp_brush brush; - int k; - int dx; - int dy; - int rop; + struct xrdp_rect clip_rect; + struct xrdp_rect draw_rect; + struct xrdp_rect rect; + struct xrdp_region *region; + struct xrdp_brush brush; + int k; + int dx; + int dy; + int rop; - if (self == 0) - { - return 0; - } - - /* todo data */ - - if (dst->type == WND_TYPE_BITMAP) /* 0 */ - { - return 0; - } - xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); - region = xrdp_region_create(self->wm); - if (dst->type != WND_TYPE_OFFSCREEN) - { - xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, - self->clip_children); - } - else - { - xrdp_region_add_rect(region, &clip_rect); - } - x += dx; - y += dy; - if (self->mix_mode == 0 && self->rop == 0xcc) - { - k = 0; - while (xrdp_region_get_rect(region, k, &rect) == 0) + if (self == 0) { - if (rect_intersect(&rect, &clip_rect, &draw_rect)) - { - libxrdp_orders_rect(self->session, x, y, cx, cy, - self->fg_color, &draw_rect); - } - k++; + return 0; } - } - else if (self->mix_mode == 0 && + + /* todo data */ + + if (dst->type == WND_TYPE_BITMAP) /* 0 */ + { + return 0; + } + + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, + self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } + + x += dx; + y += dy; + + if (self->mix_mode == 0 && self->rop == 0xcc) + { + k = 0; + + while (xrdp_region_get_rect(region, k, &rect) == 0) + { + if (rect_intersect(&rect, &clip_rect, &draw_rect)) + { + libxrdp_orders_rect(self->session, x, y, cx, cy, + self->fg_color, &draw_rect); + } + + k++; + } + } + else if (self->mix_mode == 0 && ((self->rop & 0xf) == 0x0 || /* black */ (self->rop & 0xf) == 0xf || /* white */ (self->rop & 0xf) == 0x5)) /* DSTINVERT */ - { - k = 0; - while (xrdp_region_get_rect(region, k, &rect) == 0) { - if (rect_intersect(&rect, &clip_rect, &draw_rect)) - { - libxrdp_orders_dest_blt(self->session, x, y, cx, cy, - self->rop, &draw_rect); - } - k++; + k = 0; + + while (xrdp_region_get_rect(region, k, &rect) == 0) + { + if (rect_intersect(&rect, &clip_rect, &draw_rect)) + { + libxrdp_orders_dest_blt(self->session, x, y, cx, cy, + self->rop, &draw_rect); + } + + k++; + } } - } - else - { - k = 0; - rop = self->rop; - /* if opcode is in the form 0x00, 0x11, 0x22, ... convert it */ - if (((rop & 0xf0) >> 4) == (rop & 0xf)) + else { - switch (rop) - { - case 0x66: /* xor */ - rop = 0x5a; - break; - case 0xaa: /* noop */ - rop = 0xfb; - break; - case 0xcc: /* copy */ - rop = 0xf0; - break; - case 0x88: /* and */ - rop = 0xc0; - break; - } + k = 0; + rop = self->rop; + + /* if opcode is in the form 0x00, 0x11, 0x22, ... convert it */ + if (((rop & 0xf0) >> 4) == (rop & 0xf)) + { + switch (rop) + { + case 0x66: /* xor */ + rop = 0x5a; + break; + case 0xaa: /* noop */ + rop = 0xfb; + break; + case 0xcc: /* copy */ + rop = 0xf0; + break; + case 0x88: /* and */ + rop = 0xc0; + break; + } + } + + xrdp_painter_setup_brush(self, &brush, &self->brush); + + while (xrdp_region_get_rect(region, k, &rect) == 0) + { + if (rect_intersect(&rect, &clip_rect, &draw_rect)) + { + libxrdp_orders_pat_blt(self->session, x, y, cx, cy, + rop, self->bg_color, self->fg_color, + &brush, &draw_rect); + } + + k++; + } } - xrdp_painter_setup_brush(self, &brush, &self->brush); - while (xrdp_region_get_rect(region, k, &rect) == 0) - { - if (rect_intersect(&rect, &clip_rect, &draw_rect)) - { - libxrdp_orders_pat_blt(self->session, x, y, cx, cy, - rop, self->bg_color, self->fg_color, - &brush, &draw_rect); - } - k++; - } - } - xrdp_region_delete(region); - return 0; + + xrdp_region_delete(region); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_painter_draw_text(struct xrdp_painter* self, - struct xrdp_bitmap* dst, - int x, int y, const char* text) +xrdp_painter_draw_text(struct xrdp_painter *self, + struct xrdp_bitmap *dst, + int x, int y, const char *text) { - int i; - int f; - int c; - int k; - int x1; - int y1; - int flags; - int len; - int index; - int total_width; - int total_height; - int dx; - int dy; - char* data; - struct xrdp_region* region; - struct xrdp_rect rect; - struct xrdp_rect clip_rect; - struct xrdp_rect draw_rect; - struct xrdp_font* font; - struct xrdp_font_char* font_item; - twchar* wstr; + int i; + int f; + int c; + int k; + int x1; + int y1; + int flags; + int len; + int index; + int total_width; + int total_height; + int dx; + int dy; + char *data; + struct xrdp_region *region; + struct xrdp_rect rect; + struct xrdp_rect clip_rect; + struct xrdp_rect draw_rect; + struct xrdp_font *font; + struct xrdp_font_char *font_item; + twchar *wstr; - if (self == 0) - { - return 0; - } - len = g_mbstowcs(0, text, 0); - if (len < 1) - { - return 0; - } - - /* todo data */ - - if (dst->type == 0) - { - return 0; - } - xrdp_painter_font_needed(self); - if (self->font == 0) - { - return 0; - } - /* convert to wide char */ - wstr = (twchar*)g_malloc((len + 2) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); - font = self->font; - f = 0; - k = 0; - total_width = 0; - total_height = 0; - data = (char*)g_malloc(len * 4, 1); - for (index = 0; index < len; index++) - { - font_item = font->font_items + wstr[index]; - i = xrdp_cache_add_char(self->wm->cache, font_item); - f = HIWORD(i); - c = LOWORD(i); - data[index * 2] = c; - data[index * 2 + 1] = k; - k = font_item->incby; - total_width += k; - total_height = MAX(total_height, font_item->height); - } - xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); - region = xrdp_region_create(self->wm); - if (dst->type != WND_TYPE_OFFSCREEN) - { - xrdp_wm_get_vis_region(self->wm, dst, x, y, total_width, total_height, - region, self->clip_children); - } - else - { - xrdp_region_add_rect(region, &clip_rect); - } - x += dx; - y += dy; - k = 0; - while (xrdp_region_get_rect(region, k, &rect) == 0) - { - if (rect_intersect(&rect, &clip_rect, &draw_rect)) + if (self == 0) { - x1 = x; - y1 = y + total_height; - flags = 0x03; /* 0x03 0x73; TEXT2_IMPLICIT_X and something else */ - libxrdp_orders_text(self->session, f, flags, 0, - self->fg_color, 0, - x - 1, y - 1, x + total_width, y + total_height, - 0, 0, 0, 0, - x1, y1, data, len * 2, &draw_rect); + return 0; } - k++; - } - xrdp_region_delete(region); - g_free(data); - g_free(wstr); - return 0; + + len = g_mbstowcs(0, text, 0); + + if (len < 1) + { + return 0; + } + + /* todo data */ + + if (dst->type == 0) + { + return 0; + } + + xrdp_painter_font_needed(self); + + if (self->font == 0) + { + return 0; + } + + /* convert to wide char */ + wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0); + g_mbstowcs(wstr, text, len + 1); + font = self->font; + f = 0; + k = 0; + total_width = 0; + total_height = 0; + data = (char *)g_malloc(len * 4, 1); + + for (index = 0; index < len; index++) + { + font_item = font->font_items + wstr[index]; + i = xrdp_cache_add_char(self->wm->cache, font_item); + f = HIWORD(i); + c = LOWORD(i); + data[index * 2] = c; + data[index * 2 + 1] = k; + k = font_item->incby; + total_width += k; + total_height = MAX(total_height, font_item->height); + } + + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, x, y, total_width, total_height, + region, self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } + + x += dx; + y += dy; + k = 0; + + while (xrdp_region_get_rect(region, k, &rect) == 0) + { + if (rect_intersect(&rect, &clip_rect, &draw_rect)) + { + x1 = x; + y1 = y + total_height; + flags = 0x03; /* 0x03 0x73; TEXT2_IMPLICIT_X and something else */ + libxrdp_orders_text(self->session, f, flags, 0, + self->fg_color, 0, + x - 1, y - 1, x + total_width, y + total_height, + 0, 0, 0, 0, + x1, y1, data, len * 2, &draw_rect); + } + + k++; + } + + xrdp_region_delete(region); + g_free(data); + g_free(wstr); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_painter_draw_text2(struct xrdp_painter* self, - struct xrdp_bitmap* dst, +xrdp_painter_draw_text2(struct xrdp_painter *self, + struct xrdp_bitmap *dst, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, - int x, int y, char* data, int data_len) + int x, int y, char *data, int data_len) { - struct xrdp_rect clip_rect; - struct xrdp_rect draw_rect; - struct xrdp_rect rect; - struct xrdp_region* region; - int k; - int dx; - int dy; + struct xrdp_rect clip_rect; + struct xrdp_rect draw_rect; + struct xrdp_rect rect; + struct xrdp_region *region; + int k; + int dx; + int dy; - if (self == 0) - { - return 0; - } - - /* todo data */ - - if (dst->type == WND_TYPE_BITMAP) - { - return 0; - } - xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); - region = xrdp_region_create(self->wm); - if (dst->type != WND_TYPE_OFFSCREEN) - { - if (box_right - box_left > 1) + if (self == 0) { - xrdp_wm_get_vis_region(self->wm, dst, box_left, box_top, - box_right - box_left, box_bottom - box_top, - region, self->clip_children); + return 0; + } + + /* todo data */ + + if (dst->type == WND_TYPE_BITMAP) + { + return 0; + } + + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + + if (dst->type != WND_TYPE_OFFSCREEN) + { + if (box_right - box_left > 1) + { + xrdp_wm_get_vis_region(self->wm, dst, box_left, box_top, + box_right - box_left, box_bottom - box_top, + region, self->clip_children); + } + else + { + xrdp_wm_get_vis_region(self->wm, dst, clip_left, clip_top, + clip_right - clip_left, clip_bottom - clip_top, + region, self->clip_children); + } } else { - xrdp_wm_get_vis_region(self->wm, dst, clip_left, clip_top, - clip_right - clip_left, clip_bottom - clip_top, - region, self->clip_children); + xrdp_region_add_rect(region, &clip_rect); } - } - else - { - xrdp_region_add_rect(region, &clip_rect); - } - clip_left += dx; - clip_top += dy; - clip_right += dx; - clip_bottom += dy; - box_left += dx; - box_top += dy; - box_right += dx; - box_bottom += dy; - x += dx; - y += dy; - k = 0; - while (xrdp_region_get_rect(region, k, &rect) == 0) - { - if (rect_intersect(&rect, &clip_rect, &draw_rect)) + clip_left += dx; + clip_top += dy; + clip_right += dx; + clip_bottom += dy; + box_left += dx; + box_top += dy; + box_right += dx; + box_bottom += dy; + x += dx; + y += dy; + k = 0; + + while (xrdp_region_get_rect(region, k, &rect) == 0) { - libxrdp_orders_text(self->session, font, flags, mixmode, - self->fg_color, self->bg_color, - clip_left, clip_top, clip_right, clip_bottom, - box_left, box_top, box_right, box_bottom, - x, y, data, data_len, &draw_rect); + if (rect_intersect(&rect, &clip_rect, &draw_rect)) + { + libxrdp_orders_text(self->session, font, flags, mixmode, + self->fg_color, self->bg_color, + clip_left, clip_top, clip_right, clip_bottom, + box_left, box_top, box_right, box_bottom, + x, y, data, data_len, &draw_rect); + } + + k++; } - k++; - } - xrdp_region_delete(region); - return 0; + + xrdp_region_delete(region); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_painter_copy(struct xrdp_painter* self, - struct xrdp_bitmap* src, - struct xrdp_bitmap* dst, +xrdp_painter_copy(struct xrdp_painter *self, + struct xrdp_bitmap *src, + struct xrdp_bitmap *dst, int x, int y, int cx, int cy, int srcx, int srcy) { - struct xrdp_rect clip_rect; - struct xrdp_rect draw_rect; - struct xrdp_rect rect1; - struct xrdp_rect rect2; - struct xrdp_region* region; - struct xrdp_bitmap* b; - int i; - int j; - int k; - int dx; - int dy; - int palette_id; - int bitmap_id; - int cache_id; - int cache_idx; - int dstx; - int dsty; - int w; - int h; + struct xrdp_rect clip_rect; + struct xrdp_rect draw_rect; + struct xrdp_rect rect1; + struct xrdp_rect rect2; + struct xrdp_region *region; + struct xrdp_bitmap *b; + int i; + int j; + int k; + int dx; + int dy; + int palette_id; + int bitmap_id; + int cache_id; + int cache_idx; + int dstx; + int dsty; + int w; + int h; - if (self == 0 || src == 0 || dst == 0) - { - return 0; - } - - /* todo data */ - - if (dst->type == WND_TYPE_BITMAP) - { - return 0; - } - if (src->type == WND_TYPE_SCREEN) - { - xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); - region = xrdp_region_create(self->wm); - if (dst->type != WND_TYPE_OFFSCREEN) + if (self == 0 || src == 0 || dst == 0) { - xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, - region, self->clip_children); + return 0; } - else - { - xrdp_region_add_rect(region, &clip_rect); - } - x += dx; - y += dy; - srcx += dx; - srcy += dy; - k = 0; - while (xrdp_region_get_rect(region, k, &rect1) == 0) - { - if (rect_intersect(&rect1, &clip_rect, &draw_rect)) - { - libxrdp_orders_screen_blt(self->session, x, y, cx, cy, - srcx, srcy, self->rop, &draw_rect); - } - k++; - } - xrdp_region_delete(region); - } - else if (src->type == WND_TYPE_OFFSCREEN) - { - //g_writeln("xrdp_painter_copy: todo"); - xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); - region = xrdp_region_create(self->wm); - if (dst->type != WND_TYPE_OFFSCREEN) - { - //g_writeln("off screen to screen"); - xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, - region, self->clip_children); - } - else - { - //g_writeln("off screen to off screen"); - xrdp_region_add_rect(region, &clip_rect); - } - x += dx; - y += dy; + /* todo data */ - palette_id = 0; - cache_id = 255; // todo - cache_idx = src->item_index; // todo - - k = 0; - while (xrdp_region_get_rect(region, k, &rect1) == 0) + if (dst->type == WND_TYPE_BITMAP) { - if (rect_intersect(&rect1, &clip_rect, &rect2)) - { - MAKERECT(rect1, x, y, cx, cy); - if (rect_intersect(&rect2, &rect1, &draw_rect)) + return 0; + } + + if (src->type == WND_TYPE_SCREEN) + { + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + + if (dst->type != WND_TYPE_OFFSCREEN) { - libxrdp_orders_mem_blt(self->session, cache_id, palette_id, - x, y, cx, cy, self->rop, srcx, srcy, - cache_idx, &draw_rect); + xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, + region, self->clip_children); } - } - k++; - } - xrdp_region_delete(region); - } - else if (src->data != 0) - /* todo, the non bitmap cache part is gone, it should be put back */ - { - xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); - region = xrdp_region_create(self->wm); - if (dst->type != WND_TYPE_OFFSCREEN) - { - xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, - region, self->clip_children); - } - else - { - xrdp_region_add_rect(region, &clip_rect); - } - x += dx; - y += dy; - palette_id = 0; - j = srcy; - while (j < (srcy + cy)) - { - i = srcx; - while (i < (srcx + cx)) - { - w = MIN(64, ((srcx + cx) - i)); - h = MIN(64, ((srcy + cy) - j)); - b = xrdp_bitmap_create(w, h, self->wm->screen->bpp, 0, self->wm); - xrdp_bitmap_copy_box_with_crc(src, b, i, j, w, h); - bitmap_id = xrdp_cache_add_bitmap(self->wm->cache, b, self->wm->hints); - cache_id = HIWORD(bitmap_id); - cache_idx = LOWORD(bitmap_id); - dstx = (x + i) - srcx; - dsty = (y + j) - srcy; + else + { + xrdp_region_add_rect(region, &clip_rect); + } + + x += dx; + y += dy; + srcx += dx; + srcy += dy; k = 0; + while (xrdp_region_get_rect(region, k, &rect1) == 0) { - if (rect_intersect(&rect1, &clip_rect, &rect2)) - { - MAKERECT(rect1, dstx, dsty, w, h); - if (rect_intersect(&rect2, &rect1, &draw_rect)) + if (rect_intersect(&rect1, &clip_rect, &draw_rect)) { - libxrdp_orders_mem_blt(self->session, cache_id, palette_id, - dstx, dsty, w, h, self->rop, 0, 0, - cache_idx, &draw_rect); + libxrdp_orders_screen_blt(self->session, x, y, cx, cy, + srcx, srcy, self->rop, &draw_rect); } - } - k++; + + k++; } - i += 64; - } - j += 64; + + xrdp_region_delete(region); } - xrdp_region_delete(region); - } - return 0; + else if (src->type == WND_TYPE_OFFSCREEN) + { + //g_writeln("xrdp_painter_copy: todo"); + + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + + if (dst->type != WND_TYPE_OFFSCREEN) + { + //g_writeln("off screen to screen"); + xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, + region, self->clip_children); + } + else + { + //g_writeln("off screen to off screen"); + xrdp_region_add_rect(region, &clip_rect); + } + + x += dx; + y += dy; + + palette_id = 0; + cache_id = 255; // todo + cache_idx = src->item_index; // todo + + k = 0; + + while (xrdp_region_get_rect(region, k, &rect1) == 0) + { + if (rect_intersect(&rect1, &clip_rect, &rect2)) + { + MAKERECT(rect1, x, y, cx, cy); + + if (rect_intersect(&rect2, &rect1, &draw_rect)) + { + libxrdp_orders_mem_blt(self->session, cache_id, palette_id, + x, y, cx, cy, self->rop, srcx, srcy, + cache_idx, &draw_rect); + } + } + + k++; + } + + xrdp_region_delete(region); + } + else if (src->data != 0) + /* todo, the non bitmap cache part is gone, it should be put back */ + { + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, + region, self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } + + x += dx; + y += dy; + palette_id = 0; + j = srcy; + + while (j < (srcy + cy)) + { + i = srcx; + + while (i < (srcx + cx)) + { + w = MIN(64, ((srcx + cx) - i)); + h = MIN(64, ((srcy + cy) - j)); + b = xrdp_bitmap_create(w, h, self->wm->screen->bpp, 0, self->wm); + xrdp_bitmap_copy_box_with_crc(src, b, i, j, w, h); + bitmap_id = xrdp_cache_add_bitmap(self->wm->cache, b, self->wm->hints); + cache_id = HIWORD(bitmap_id); + cache_idx = LOWORD(bitmap_id); + dstx = (x + i) - srcx; + dsty = (y + j) - srcy; + k = 0; + + while (xrdp_region_get_rect(region, k, &rect1) == 0) + { + if (rect_intersect(&rect1, &clip_rect, &rect2)) + { + MAKERECT(rect1, dstx, dsty, w, h); + + if (rect_intersect(&rect2, &rect1, &draw_rect)) + { + libxrdp_orders_mem_blt(self->session, cache_id, palette_id, + dstx, dsty, w, h, self->rop, 0, 0, + cache_idx, &draw_rect); + } + } + + k++; + } + + i += 64; + } + + j += 64; + } + + xrdp_region_delete(region); + } + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_painter_line(struct xrdp_painter* self, - struct xrdp_bitmap* dst, +xrdp_painter_line(struct xrdp_painter *self, + struct xrdp_bitmap *dst, int x1, int y1, int x2, int y2) { - struct xrdp_rect clip_rect; - struct xrdp_rect draw_rect; - struct xrdp_rect rect; - struct xrdp_region* region; - int k; - int dx; - int dy; - int rop; + struct xrdp_rect clip_rect; + struct xrdp_rect draw_rect; + struct xrdp_rect rect; + struct xrdp_region *region; + int k; + int dx; + int dy; + int rop; - if (self == 0) - { - return 0; - } - - /* todo data */ - - if (dst->type == WND_TYPE_BITMAP) - { - return 0; - } - xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); - region = xrdp_region_create(self->wm); - if (dst->type != WND_TYPE_OFFSCREEN) - { - xrdp_wm_get_vis_region(self->wm, dst, MIN(x1, x2), MIN(y1, y2), - g_abs(x1 - x2) + 1, g_abs(y1 - y2) + 1, - region, self->clip_children); - } - else - { - xrdp_region_add_rect(region, &clip_rect); - } - x1 += dx; - y1 += dy; - x2 += dx; - y2 += dy; - k = 0; - rop = self->rop; - if (rop < 0x01 || rop > 0x10) - { - rop = (rop & 0xf) + 1; - } - while (xrdp_region_get_rect(region, k, &rect) == 0) - { - if (rect_intersect(&rect, &clip_rect, &draw_rect)) + if (self == 0) { - libxrdp_orders_line(self->session, 1, x1, y1, x2, y2, - rop, self->bg_color, - &self->pen, &draw_rect); + return 0; } - k++; - } - xrdp_region_delete(region); - return 0; + + /* todo data */ + + if (dst->type == WND_TYPE_BITMAP) + { + return 0; + } + + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, MIN(x1, x2), MIN(y1, y2), + g_abs(x1 - x2) + 1, g_abs(y1 - y2) + 1, + region, self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } + + x1 += dx; + y1 += dy; + x2 += dx; + y2 += dy; + k = 0; + rop = self->rop; + + if (rop < 0x01 || rop > 0x10) + { + rop = (rop & 0xf) + 1; + } + + while (xrdp_region_get_rect(region, k, &rect) == 0) + { + if (rect_intersect(&rect, &clip_rect, &draw_rect)) + { + libxrdp_orders_line(self->session, 1, x1, y1, x2, y2, + rop, self->bg_color, + &self->pen, &draw_rect); + } + + k++; + } + + xrdp_region_delete(region); + return 0; } diff --git a/xrdp/xrdp_process.c b/xrdp/xrdp_process.c index 7a88d524..e3b846ea 100644 --- a/xrdp/xrdp_process.c +++ b/xrdp/xrdp_process.c @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - main rdp process - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * main rdp process + */ #include "xrdp.h" @@ -26,60 +24,64 @@ static int g_session_id = 0; /*****************************************************************************/ /* always called from xrdp_listen thread */ -struct xrdp_process* APP_CC -xrdp_process_create(struct xrdp_listen* owner, tbus done_event) +struct xrdp_process *APP_CC +xrdp_process_create(struct xrdp_listen *owner, tbus done_event) { - struct xrdp_process* self; - char event_name[256]; - int pid; + struct xrdp_process *self; + char event_name[256]; + int pid; - self = (struct xrdp_process*)g_malloc(sizeof(struct xrdp_process), 1); - self->lis_layer = owner; - self->done_event = done_event; - g_session_id++; - self->session_id = g_session_id; - pid = g_getpid(); - g_snprintf(event_name, 255, "xrdp_%8.8x_process_self_term_event_%8.8x", - pid, self->session_id); - self->self_term_event = g_create_wait_obj(event_name); - return self; + self = (struct xrdp_process *)g_malloc(sizeof(struct xrdp_process), 1); + self->lis_layer = owner; + self->done_event = done_event; + g_session_id++; + self->session_id = g_session_id; + pid = g_getpid(); + g_snprintf(event_name, 255, "xrdp_%8.8x_process_self_term_event_%8.8x", + pid, self->session_id); + self->self_term_event = g_create_wait_obj(event_name); + return self; } /*****************************************************************************/ void APP_CC -xrdp_process_delete(struct xrdp_process* self) +xrdp_process_delete(struct xrdp_process *self) { - if (self == 0) - { - return; - } - g_delete_wait_obj(self->self_term_event); - libxrdp_exit(self->session); - xrdp_wm_delete(self->wm); - trans_delete(self->server_trans); - g_free(self); + if (self == 0) + { + return; + } + + g_delete_wait_obj(self->self_term_event); + libxrdp_exit(self->session); + xrdp_wm_delete(self->wm); + trans_delete(self->server_trans); + g_free(self); } /*****************************************************************************/ static int APP_CC -xrdp_process_loop(struct xrdp_process* self) +xrdp_process_loop(struct xrdp_process *self) { - int rv; + int rv; - rv = 0; - if (self->session != 0) - { - rv = libxrdp_process_data(self->session); - } - if ((self->wm == 0) && (self->session->up_and_running) && (rv == 0)) - { - DEBUG(("calling xrdp_wm_init and creating wm")); - self->wm = xrdp_wm_create(self, self->session->client_info); - /* at this point the wm(window manager) is create and wm::login_mode is - zero and login_mode_event is set so xrdp_wm_init should be called by - xrdp_wm_check_wait_objs */ - } - return rv; + rv = 0; + + if (self->session != 0) + { + rv = libxrdp_process_data(self->session); + } + + if ((self->wm == 0) && (self->session->up_and_running) && (rv == 0)) + { + DEBUG(("calling xrdp_wm_init and creating wm")); + self->wm = xrdp_wm_create(self, self->session->client_info); + /* at this point the wm(window manager) is create and wm::login_mode is + zero and login_mode_event is set so xrdp_wm_init should be called by + xrdp_wm_check_wait_objs */ + } + + return rv; } /*****************************************************************************/ @@ -88,113 +90,125 @@ xrdp_process_loop(struct xrdp_process* self) static int DEFAULT_CC xrdp_is_term(void) { - return g_is_term(); + return g_is_term(); } /*****************************************************************************/ static int APP_CC -xrdp_process_mod_end(struct xrdp_process* self) +xrdp_process_mod_end(struct xrdp_process *self) { - if (self->wm != 0) - { - if (self->wm->mm != 0) + if (self->wm != 0) { - if (self->wm->mm->mod != 0) - { - if (self->wm->mm->mod->mod_end != 0) + if (self->wm->mm != 0) { - return self->wm->mm->mod->mod_end(self->wm->mm->mod); + if (self->wm->mm->mod != 0) + { + if (self->wm->mm->mod->mod_end != 0) + { + return self->wm->mm->mod->mod_end(self->wm->mm->mod); + } + } } - } } - } - return 0; + + return 0; } /*****************************************************************************/ static int DEFAULT_CC -xrdp_process_data_in(struct trans* self) +xrdp_process_data_in(struct trans *self) { - struct xrdp_process* pro; + struct xrdp_process *pro; - DEBUG(("xrdp_process_data_in")); - pro = (struct xrdp_process*)(self->callback_data); - if (xrdp_process_loop(pro) != 0) - { - return 1; - } - return 0; + DEBUG(("xrdp_process_data_in")); + pro = (struct xrdp_process *)(self->callback_data); + + if (xrdp_process_loop(pro) != 0) + { + return 1; + } + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_process_main_loop(struct xrdp_process* self) +xrdp_process_main_loop(struct xrdp_process *self) { - int robjs_count; - int wobjs_count; - int cont; - int timeout = 0; - tbus robjs[32]; - tbus wobjs[32]; - tbus term_obj; + int robjs_count; + int wobjs_count; + int cont; + int timeout = 0; + tbus robjs[32]; + tbus wobjs[32]; + tbus term_obj; - DEBUG(("xrdp_process_main_loop")); - self->status = 1; - self->server_trans->trans_data_in = xrdp_process_data_in; - self->server_trans->callback_data = self; - self->session = libxrdp_init((tbus)self, self->server_trans); - /* this callback function is in xrdp_wm.c */ - self->session->callback = callback; - /* this function is just above */ - self->session->is_term = xrdp_is_term; - if (libxrdp_process_incomming(self->session) == 0) - { - term_obj = g_get_term_event(); - cont = 1; - while (cont) + DEBUG(("xrdp_process_main_loop")); + self->status = 1; + self->server_trans->trans_data_in = xrdp_process_data_in; + self->server_trans->callback_data = self; + self->session = libxrdp_init((tbus)self, self->server_trans); + /* this callback function is in xrdp_wm.c */ + self->session->callback = callback; + /* this function is just above */ + self->session->is_term = xrdp_is_term; + + if (libxrdp_process_incomming(self->session) == 0) { - /* build the wait obj list */ - timeout = -1; - robjs_count = 0; - wobjs_count = 0; - robjs[robjs_count++] = term_obj; - robjs[robjs_count++] = self->self_term_event; - xrdp_wm_get_wait_objs(self->wm, robjs, &robjs_count, - wobjs, &wobjs_count, &timeout); - trans_get_wait_objs(self->server_trans, robjs, &robjs_count); - /* wait */ - if (g_obj_wait(robjs, robjs_count, wobjs, wobjs_count, timeout) != 0) - { - /* error, should not get here */ - g_sleep(100); - } - if (g_is_wait_obj_set(term_obj)) /* term */ - { - break; - } - if (g_is_wait_obj_set(self->self_term_event)) - { - break; - } - if (xrdp_wm_check_wait_objs(self->wm) != 0) - { - break; - } - if (trans_check_wait_objs(self->server_trans) != 0) - { - break; - } + term_obj = g_get_term_event(); + cont = 1; + + while (cont) + { + /* build the wait obj list */ + timeout = -1; + robjs_count = 0; + wobjs_count = 0; + robjs[robjs_count++] = term_obj; + robjs[robjs_count++] = self->self_term_event; + xrdp_wm_get_wait_objs(self->wm, robjs, &robjs_count, + wobjs, &wobjs_count, &timeout); + trans_get_wait_objs(self->server_trans, robjs, &robjs_count); + + /* wait */ + if (g_obj_wait(robjs, robjs_count, wobjs, wobjs_count, timeout) != 0) + { + /* error, should not get here */ + g_sleep(100); + } + + if (g_is_wait_obj_set(term_obj)) /* term */ + { + break; + } + + if (g_is_wait_obj_set(self->self_term_event)) + { + break; + } + + if (xrdp_wm_check_wait_objs(self->wm) != 0) + { + break; + } + + if (trans_check_wait_objs(self->server_trans) != 0) + { + break; + } + } + + libxrdp_disconnect(self->session); } - libxrdp_disconnect(self->session); - } - else - { - g_writeln("xrdp_process_main_loop: libxrdp_process_incomming failed"); - } - xrdp_process_mod_end(self); - libxrdp_exit(self->session); - self->session = 0; - self->status = -1; - g_set_wait_obj(self->done_event); - return 0; + else + { + g_writeln("xrdp_process_main_loop: libxrdp_process_incomming failed"); + } + + xrdp_process_mod_end(self); + libxrdp_exit(self->session); + self->session = 0; + self->status = -1; + g_set_wait_obj(self->done_event); + return 0; } diff --git a/xrdp/xrdp_region.c b/xrdp/xrdp_region.c index db046a30..8dc6854b 100644 --- a/xrdp/xrdp_region.c +++ b/xrdp/xrdp_region.c @@ -1,297 +1,316 @@ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - region - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * region + */ #include "xrdp.h" /*****************************************************************************/ -struct xrdp_region* APP_CC -xrdp_region_create(struct xrdp_wm* wm) +struct xrdp_region *APP_CC +xrdp_region_create(struct xrdp_wm *wm) { - struct xrdp_region* self; + struct xrdp_region *self; - self = (struct xrdp_region*)g_malloc(sizeof(struct xrdp_region), 1); - self->wm = wm; - self->rects = list_create(); - self->rects->auto_free = 1; - return self; + self = (struct xrdp_region *)g_malloc(sizeof(struct xrdp_region), 1); + self->wm = wm; + self->rects = list_create(); + self->rects->auto_free = 1; + return self; } /*****************************************************************************/ void APP_CC -xrdp_region_delete(struct xrdp_region* self) +xrdp_region_delete(struct xrdp_region *self) { - if (self == 0) - { - return; - } - list_delete(self->rects); - g_free(self); + if (self == 0) + { + return; + } + + list_delete(self->rects); + g_free(self); } /*****************************************************************************/ int APP_CC -xrdp_region_add_rect(struct xrdp_region* self, struct xrdp_rect* rect) +xrdp_region_add_rect(struct xrdp_region *self, struct xrdp_rect *rect) { - struct xrdp_rect* r; + struct xrdp_rect *r; - r = (struct xrdp_rect*)g_malloc(sizeof(struct xrdp_rect), 1); - *r = *rect; - list_add_item(self->rects, (long)r); - return 0; + r = (struct xrdp_rect *)g_malloc(sizeof(struct xrdp_rect), 1); + *r = *rect; + list_add_item(self->rects, (long)r); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_region_insert_rect(struct xrdp_region* self, int i, int left, +xrdp_region_insert_rect(struct xrdp_region *self, int i, int left, int top, int right, int bottom) { - struct xrdp_rect* r; + struct xrdp_rect *r; - r = (struct xrdp_rect*)g_malloc(sizeof(struct xrdp_rect), 1); - r->left = left; - r->top = top; - r->right = right; - r->bottom = bottom; - list_insert_item(self->rects, i, (long)r); - return 0; + r = (struct xrdp_rect *)g_malloc(sizeof(struct xrdp_rect), 1); + r->left = left; + r->top = top; + r->right = right; + r->bottom = bottom; + list_insert_item(self->rects, i, (long)r); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_region_subtract_rect(struct xrdp_region* self, - struct xrdp_rect* rect) +xrdp_region_subtract_rect(struct xrdp_region *self, + struct xrdp_rect *rect) { - struct xrdp_rect* r; - struct xrdp_rect rect1; - int i; + struct xrdp_rect *r; + struct xrdp_rect rect1; + int i; - for (i = self->rects->count - 1; i >= 0; i--) - { - r = (struct xrdp_rect*)list_get_item(self->rects, i); - rect1 = *r; - r = &rect1; - if (rect->left <= r->left && - rect->top <= r->top && - rect->right >= r->right && - rect->bottom >= r->bottom) - { /* rect is not visible */ - list_remove_item(self->rects, i); - } - else if (rect->right < r->left || - rect->bottom < r->top || - rect->top > r->bottom || - rect->left > r->right) - { /* rect are not related */ - } - else if (rect->left <= r->left && - rect->right >= r->right && - rect->bottom < r->bottom && - rect->top <= r->top) - { /* partially covered(whole top) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, rect->bottom, - r->right, r->bottom); - } - else if (rect->top <= r->top && - rect->bottom >= r->bottom && - rect->right < r->right && - rect->left <= r->left) - { /* partially covered(left) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, rect->right, r->top, - r->right, r->bottom); - } - else if (rect->left <= r->left && - rect->right >= r->right && - rect->top > r->top && - rect->bottom >= r->bottom) - { /* partially covered(bottom) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - r->right, rect->top); - } - else if (rect->top <= r->top && - rect->bottom >= r->bottom && - rect->left > r->left && - rect->right >= r->right) - { /* partially covered(right) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - rect->left, r->bottom); - } - else if (rect->left <= r->left && - rect->top <= r->top && - rect->right < r->right && - rect->bottom < r->bottom) - { /* partially covered(top left) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, rect->right, r->top, - r->right, rect->bottom); - xrdp_region_insert_rect(self, i, r->left, rect->bottom, - r->right, r->bottom); - } - else if (rect->left <= r->left && - rect->bottom >= r->bottom && - rect->right < r->right && - rect->top > r->top) - { /* partially covered(bottom left) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - r->right, rect->top); - xrdp_region_insert_rect(self, i, rect->right, rect->top, - r->right, r->bottom); - } - else if (rect->left > r->left && - rect->right >= r->right && - rect->top <= r->top && - rect->bottom < r->bottom) - { /* partially covered(top right) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - rect->left, r->bottom); - xrdp_region_insert_rect(self, i, rect->left, rect->bottom, - r->right, r->bottom); - } - else if (rect->left > r->left && - rect->right >= r->right && - rect->top > r->top && - rect->bottom >= r->bottom) - { /* partially covered(bottom right) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - r->right, rect->top); - xrdp_region_insert_rect(self, i, r->left, rect->top, - rect->left, r->bottom); - } - else if (rect->left > r->left && - rect->top <= r->top && - rect->right < r->right && - rect->bottom >= r->bottom) - { /* 2 rects, one on each end */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - rect->left, r->bottom); - xrdp_region_insert_rect(self, i, rect->right, r->top, - r->right, r->bottom); - } - else if (rect->left <= r->left && - rect->top > r->top && - rect->right >= r->right && - rect->bottom < r->bottom) - { /* 2 rects, one on each end */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - r->right, rect->top); - xrdp_region_insert_rect(self, i, r->left, rect->bottom, - r->right, r->bottom); - } - else if (rect->left > r->left && - rect->right < r->right && - rect->top <= r->top && - rect->bottom < r->bottom) - { /* partially covered(top) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - rect->left, r->bottom); - xrdp_region_insert_rect(self, i, rect->left, rect->bottom, - rect->right, r->bottom); - xrdp_region_insert_rect(self, i, rect->right, r->top, - r->right, r->bottom); - } - else if (rect->top > r->top && - rect->bottom < r->bottom && - rect->left <= r->left && - rect->right < r->right) - { /* partially covered(left) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - r->right, rect->top); - xrdp_region_insert_rect(self, i, rect->right, rect->top, - r->right, rect->bottom); - xrdp_region_insert_rect(self, i, r->left, rect->bottom, - r->right, r->bottom); - } - else if (rect->left > r->left && - rect->right < r->right && - rect->bottom >= r->bottom && - rect->top > r->top) - { /* partially covered(bottom) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - rect->left, r->bottom); - xrdp_region_insert_rect(self, i, rect->left, r->top, - rect->right, rect->top); - xrdp_region_insert_rect(self, i, rect->right, r->top, - r->right, r->bottom); - } - else if (rect->top > r->top && - rect->bottom < r->bottom && - rect->right >= r->right && - rect->left > r->left) - { /* partially covered(right) */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - r->right, rect->top); - xrdp_region_insert_rect(self, i, r->left, rect->top, - rect->left, rect->bottom); - xrdp_region_insert_rect(self, i, r->left, rect->bottom, - r->right, r->bottom); - } - else if (rect->left > r->left && - rect->top > r->top && - rect->right < r->right && - rect->bottom < r->bottom) - { /* totally contained, 4 rects */ - list_remove_item(self->rects, i); - xrdp_region_insert_rect(self, i, r->left, r->top, - r->right, rect->top); - xrdp_region_insert_rect(self, i, r->left, rect->top, - rect->left, rect->bottom); - xrdp_region_insert_rect(self, i, r->left, rect->bottom, - r->right, r->bottom); - xrdp_region_insert_rect(self, i, rect->right, rect->top, - r->right, rect->bottom); - } - else + for (i = self->rects->count - 1; i >= 0; i--) { - g_writeln("error in xrdp_region_subtract_rect"); + r = (struct xrdp_rect *)list_get_item(self->rects, i); + rect1 = *r; + r = &rect1; + + if (rect->left <= r->left && + rect->top <= r->top && + rect->right >= r->right && + rect->bottom >= r->bottom) + { + /* rect is not visible */ + list_remove_item(self->rects, i); + } + else if (rect->right < r->left || + rect->bottom < r->top || + rect->top > r->bottom || + rect->left > r->right) + { + /* rect are not related */ + } + else if (rect->left <= r->left && + rect->right >= r->right && + rect->bottom < r->bottom && + rect->top <= r->top) + { + /* partially covered(whole top) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, rect->bottom, + r->right, r->bottom); + } + else if (rect->top <= r->top && + rect->bottom >= r->bottom && + rect->right < r->right && + rect->left <= r->left) + { + /* partially covered(left) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, rect->right, r->top, + r->right, r->bottom); + } + else if (rect->left <= r->left && + rect->right >= r->right && + rect->top > r->top && + rect->bottom >= r->bottom) + { + /* partially covered(bottom) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + r->right, rect->top); + } + else if (rect->top <= r->top && + rect->bottom >= r->bottom && + rect->left > r->left && + rect->right >= r->right) + { + /* partially covered(right) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + rect->left, r->bottom); + } + else if (rect->left <= r->left && + rect->top <= r->top && + rect->right < r->right && + rect->bottom < r->bottom) + { + /* partially covered(top left) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, rect->right, r->top, + r->right, rect->bottom); + xrdp_region_insert_rect(self, i, r->left, rect->bottom, + r->right, r->bottom); + } + else if (rect->left <= r->left && + rect->bottom >= r->bottom && + rect->right < r->right && + rect->top > r->top) + { + /* partially covered(bottom left) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + r->right, rect->top); + xrdp_region_insert_rect(self, i, rect->right, rect->top, + r->right, r->bottom); + } + else if (rect->left > r->left && + rect->right >= r->right && + rect->top <= r->top && + rect->bottom < r->bottom) + { + /* partially covered(top right) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + rect->left, r->bottom); + xrdp_region_insert_rect(self, i, rect->left, rect->bottom, + r->right, r->bottom); + } + else if (rect->left > r->left && + rect->right >= r->right && + rect->top > r->top && + rect->bottom >= r->bottom) + { + /* partially covered(bottom right) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + r->right, rect->top); + xrdp_region_insert_rect(self, i, r->left, rect->top, + rect->left, r->bottom); + } + else if (rect->left > r->left && + rect->top <= r->top && + rect->right < r->right && + rect->bottom >= r->bottom) + { + /* 2 rects, one on each end */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + rect->left, r->bottom); + xrdp_region_insert_rect(self, i, rect->right, r->top, + r->right, r->bottom); + } + else if (rect->left <= r->left && + rect->top > r->top && + rect->right >= r->right && + rect->bottom < r->bottom) + { + /* 2 rects, one on each end */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + r->right, rect->top); + xrdp_region_insert_rect(self, i, r->left, rect->bottom, + r->right, r->bottom); + } + else if (rect->left > r->left && + rect->right < r->right && + rect->top <= r->top && + rect->bottom < r->bottom) + { + /* partially covered(top) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + rect->left, r->bottom); + xrdp_region_insert_rect(self, i, rect->left, rect->bottom, + rect->right, r->bottom); + xrdp_region_insert_rect(self, i, rect->right, r->top, + r->right, r->bottom); + } + else if (rect->top > r->top && + rect->bottom < r->bottom && + rect->left <= r->left && + rect->right < r->right) + { + /* partially covered(left) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + r->right, rect->top); + xrdp_region_insert_rect(self, i, rect->right, rect->top, + r->right, rect->bottom); + xrdp_region_insert_rect(self, i, r->left, rect->bottom, + r->right, r->bottom); + } + else if (rect->left > r->left && + rect->right < r->right && + rect->bottom >= r->bottom && + rect->top > r->top) + { + /* partially covered(bottom) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + rect->left, r->bottom); + xrdp_region_insert_rect(self, i, rect->left, r->top, + rect->right, rect->top); + xrdp_region_insert_rect(self, i, rect->right, r->top, + r->right, r->bottom); + } + else if (rect->top > r->top && + rect->bottom < r->bottom && + rect->right >= r->right && + rect->left > r->left) + { + /* partially covered(right) */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + r->right, rect->top); + xrdp_region_insert_rect(self, i, r->left, rect->top, + rect->left, rect->bottom); + xrdp_region_insert_rect(self, i, r->left, rect->bottom, + r->right, r->bottom); + } + else if (rect->left > r->left && + rect->top > r->top && + rect->right < r->right && + rect->bottom < r->bottom) + { + /* totally contained, 4 rects */ + list_remove_item(self->rects, i); + xrdp_region_insert_rect(self, i, r->left, r->top, + r->right, rect->top); + xrdp_region_insert_rect(self, i, r->left, rect->top, + rect->left, rect->bottom); + xrdp_region_insert_rect(self, i, r->left, rect->bottom, + r->right, r->bottom); + xrdp_region_insert_rect(self, i, rect->right, rect->top, + r->right, rect->bottom); + } + else + { + g_writeln("error in xrdp_region_subtract_rect"); + } } - } - return 0; + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_region_get_rect(struct xrdp_region* self, int index, - struct xrdp_rect* rect) +xrdp_region_get_rect(struct xrdp_region *self, int index, + struct xrdp_rect *rect) { - struct xrdp_rect* r; + struct xrdp_rect *r; - r = (struct xrdp_rect*)list_get_item(self->rects, index); - if (r == 0) - { - return 1; - } - *rect = *r; - return 0; + r = (struct xrdp_rect *)list_get_item(self->rects, index); + + if (r == 0) + { + return 1; + } + + *rect = *r; + return 0; } diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index e907e2a0..fdaed059 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -1,24 +1,23 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * types + */ - 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. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - types - -*/ #define DEFAULT_STRING_LEN 255 #define LOG_WINDOW_CHAR_PER_LINE 60 diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 7883d33e..24362f54 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -1,1383 +1,1528 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 - - simple window manager - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * simple window manager + */ #include "xrdp.h" /*****************************************************************************/ -struct xrdp_wm* APP_CC -xrdp_wm_create(struct xrdp_process* owner, - struct xrdp_client_info* client_info) +struct xrdp_wm *APP_CC +xrdp_wm_create(struct xrdp_process *owner, + struct xrdp_client_info *client_info) { - struct xrdp_wm* self = (struct xrdp_wm *)NULL; - char event_name[256]; - int pid = 0; + struct xrdp_wm *self = (struct xrdp_wm *)NULL; + char event_name[256]; + int pid = 0; - /* initialize (zero out) local variables: */ - g_memset(event_name,0,sizeof(char) * 256); + /* initialize (zero out) local variables: */ + g_memset(event_name, 0, sizeof(char) * 256); - self = (struct xrdp_wm*)g_malloc(sizeof(struct xrdp_wm), 1); - self->client_info = client_info; - self->screen = xrdp_bitmap_create(client_info->width, - client_info->height, - client_info->bpp, - WND_TYPE_SCREEN, self); - self->screen->wm = self; - self->pro_layer = owner; - self->session = owner->session; - pid = g_getpid(); - g_snprintf(event_name, 255, "xrdp_%8.8x_wm_login_mode_event_%8.8x", - pid, owner->session_id); - self->login_mode_event = g_create_wait_obj(event_name); - self->painter = xrdp_painter_create(self, self->session); - self->cache = xrdp_cache_create(self, self->session, self->client_info); - self->log = list_create(); - self->log->auto_free = 1; - self->mm = xrdp_mm_create(self); - self->default_font = xrdp_font_create(self); - /* this will use built in keymap or load from file */ - get_keymaps(self->session->client_info->keylayout, &(self->keymap)); - xrdp_wm_set_login_mode(self, 0); - self->target_surface = self->screen; - self->current_surface_index = 0xffff; /* screen */ - return self; + self = (struct xrdp_wm *)g_malloc(sizeof(struct xrdp_wm), 1); + self->client_info = client_info; + self->screen = xrdp_bitmap_create(client_info->width, + client_info->height, + client_info->bpp, + WND_TYPE_SCREEN, self); + self->screen->wm = self; + self->pro_layer = owner; + self->session = owner->session; + pid = g_getpid(); + g_snprintf(event_name, 255, "xrdp_%8.8x_wm_login_mode_event_%8.8x", + pid, owner->session_id); + self->login_mode_event = g_create_wait_obj(event_name); + self->painter = xrdp_painter_create(self, self->session); + self->cache = xrdp_cache_create(self, self->session, self->client_info); + self->log = list_create(); + self->log->auto_free = 1; + self->mm = xrdp_mm_create(self); + self->default_font = xrdp_font_create(self); + /* this will use built in keymap or load from file */ + get_keymaps(self->session->client_info->keylayout, &(self->keymap)); + xrdp_wm_set_login_mode(self, 0); + self->target_surface = self->screen; + self->current_surface_index = 0xffff; /* screen */ + return self; } /*****************************************************************************/ void APP_CC -xrdp_wm_delete(struct xrdp_wm* self) +xrdp_wm_delete(struct xrdp_wm *self) { - if (self == 0) - { - return; - } - xrdp_mm_delete(self->mm); - xrdp_cache_delete(self->cache); - xrdp_painter_delete(self->painter); - xrdp_bitmap_delete(self->screen); - /* free the log */ - list_delete(self->log); - /* free default font */ - xrdp_font_delete(self->default_font); - g_delete_wait_obj(self->login_mode_event); - /* free self */ - g_free(self); + if (self == 0) + { + return; + } + + xrdp_mm_delete(self->mm); + xrdp_cache_delete(self->cache); + xrdp_painter_delete(self->painter); + xrdp_bitmap_delete(self->screen); + /* free the log */ + list_delete(self->log); + /* free default font */ + xrdp_font_delete(self->default_font); + g_delete_wait_obj(self->login_mode_event); + /* free self */ + g_free(self); } /*****************************************************************************/ int APP_CC -xrdp_wm_send_palette(struct xrdp_wm* self) +xrdp_wm_send_palette(struct xrdp_wm *self) { - return libxrdp_send_palette(self->session, self->palette); + return libxrdp_send_palette(self->session, self->palette); } /*****************************************************************************/ int APP_CC -xrdp_wm_send_bell(struct xrdp_wm* self) +xrdp_wm_send_bell(struct xrdp_wm *self) { - return libxrdp_send_bell(self->session); + return libxrdp_send_bell(self->session); } /*****************************************************************************/ int APP_CC -xrdp_wm_send_bitmap(struct xrdp_wm* self, struct xrdp_bitmap* bitmap, +xrdp_wm_send_bitmap(struct xrdp_wm *self, struct xrdp_bitmap *bitmap, int x, int y, int cx, int cy) { - return libxrdp_send_bitmap(self->session, bitmap->width, bitmap->height, - bitmap->bpp, bitmap->data, x, y, cx, cy); + return libxrdp_send_bitmap(self->session, bitmap->width, bitmap->height, + bitmap->bpp, bitmap->data, x, y, cx, cy); } /*****************************************************************************/ int APP_CC -xrdp_wm_set_focused(struct xrdp_wm* self, struct xrdp_bitmap* wnd) +xrdp_wm_set_focused(struct xrdp_wm *self, struct xrdp_bitmap *wnd) { - struct xrdp_bitmap* focus_out_control; - struct xrdp_bitmap* focus_in_control; + struct xrdp_bitmap *focus_out_control; + struct xrdp_bitmap *focus_in_control; - if (self == 0) - { + if (self == 0) + { + return 0; + } + + if (self->focused_window == wnd) + { + return 0; + } + + focus_out_control = 0; + focus_in_control = 0; + + if (self->focused_window != 0) + { + xrdp_bitmap_set_focus(self->focused_window, 0); + focus_out_control = self->focused_window->focused_control; + } + + self->focused_window = wnd; + + if (self->focused_window != 0) + { + xrdp_bitmap_set_focus(self->focused_window, 1); + focus_in_control = self->focused_window->focused_control; + } + + xrdp_bitmap_invalidate(focus_out_control, 0); + xrdp_bitmap_invalidate(focus_in_control, 0); return 0; - } - if (self->focused_window == wnd) - { - return 0; - } - focus_out_control = 0; - focus_in_control = 0; - if (self->focused_window != 0) - { - xrdp_bitmap_set_focus(self->focused_window, 0); - focus_out_control = self->focused_window->focused_control; - } - self->focused_window = wnd; - if (self->focused_window != 0) - { - xrdp_bitmap_set_focus(self->focused_window, 1); - focus_in_control = self->focused_window->focused_control; - } - xrdp_bitmap_invalidate(focus_out_control, 0); - xrdp_bitmap_invalidate(focus_in_control, 0); - return 0; } /******************************************************************************/ static int APP_CC -xrdp_wm_get_pixel(char* data, int x, int y, int width, int bpp) +xrdp_wm_get_pixel(char *data, int x, int y, int width, int bpp) { - int start; - int shift; + int start; + int shift; - if (bpp == 1) - { - width = (width + 7) / 8; - start = (y * width) + x / 8; - shift = x % 8; - return (data[start] & (0x80 >> shift)) != 0; - } - else if (bpp == 4) - { - width = (width + 1) / 2; - start = y * width + x / 2; - shift = x % 2; - if (shift == 0) + if (bpp == 1) { - return (data[start] & 0xf0) >> 4; + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + return (data[start] & (0x80 >> shift)) != 0; } - else + else if (bpp == 4) { - return data[start] & 0x0f; + width = (width + 1) / 2; + start = y * width + x / 2; + shift = x % 2; + + if (shift == 0) + { + return (data[start] & 0xf0) >> 4; + } + else + { + return data[start] & 0x0f; + } } - } - return 0; + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_wm_pointer(struct xrdp_wm* self, char* data, char* mask, int x, int y) +xrdp_wm_pointer(struct xrdp_wm *self, char *data, char *mask, int x, int y) { - struct xrdp_pointer_item pointer_item; + struct xrdp_pointer_item pointer_item; - g_memset(&pointer_item, 0, sizeof(struct xrdp_pointer_item)); - pointer_item.x = x; - pointer_item.y = y; - g_memcpy(pointer_item.data, data, 32 * 32 * 3); - g_memcpy(pointer_item.mask, mask, 32 * 32 / 8); - self->screen->pointer = xrdp_cache_add_pointer(self->cache, &pointer_item); - return 0; + g_memset(&pointer_item, 0, sizeof(struct xrdp_pointer_item)); + pointer_item.x = x; + pointer_item.y = y; + g_memcpy(pointer_item.data, data, 32 * 32 * 3); + g_memcpy(pointer_item.mask, mask, 32 * 32 / 8); + self->screen->pointer = xrdp_cache_add_pointer(self->cache, &pointer_item); + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_wm_load_pointer(struct xrdp_wm* self, char* file_name, char* data, - char* mask, int* x, int* y) +xrdp_wm_load_pointer(struct xrdp_wm *self, char *file_name, char *data, + char *mask, int *x, int *y) { - int fd; - int bpp; - int w; - int h; - int i; - int j; - int pixel; - int palette[16]; - struct stream* fs; + int fd; + int bpp; + int w; + int h; + int i; + int j; + int pixel; + int palette[16]; + struct stream *fs; - if (!g_file_exist(file_name)) - { - g_writeln("xrdp_wm_load_pointer: error pointer file [%s] does not exist", - file_name); - return 1; - } - make_stream(fs); - init_stream(fs, 8192); - fd = g_file_open(file_name); - if (fd < 1) - { - g_writeln("xrdp_wm_load_pointer: error loading pointer from file [%s]", - file_name); - return 1; - } - g_file_read(fd, fs->data, 8192); - g_file_close(fd); - in_uint8s(fs, 6); - in_uint8(fs, w); - in_uint8(fs, h); - in_uint8s(fs, 2); - in_uint16_le(fs, *x); - in_uint16_le(fs, *y); - in_uint8s(fs, 22); - in_uint8(fs, bpp); - in_uint8s(fs, 25); - if (w == 32 && h == 32) - { - if (bpp == 1) + if (!g_file_exist(file_name)) { - in_uint8a(fs, palette, 8); - for (i = 0; i < 32; i++) - { - for (j = 0; j < 32; j++) - { - pixel = palette[xrdp_wm_get_pixel(fs->p, j, i, 32, 1)]; - *data = pixel; - data++; - *data = pixel >> 8; - data++; - *data = pixel >> 16; - data++; - } - } - in_uint8s(fs, 128); + g_writeln("xrdp_wm_load_pointer: error pointer file [%s] does not exist", + file_name); + return 1; } - else if (bpp == 4) + + make_stream(fs); + init_stream(fs, 8192); + fd = g_file_open(file_name); + + if (fd < 1) { - in_uint8a(fs, palette, 64); - for (i = 0; i < 32; i++) - { - for (j = 0; j < 32; j++) - { - pixel = palette[xrdp_wm_get_pixel(fs->p, j, i, 32, 1)]; - *data = pixel; - data++; - *data = pixel >> 8; - data++; - *data = pixel >> 16; - data++; - } - } - in_uint8s(fs, 512); + g_writeln("xrdp_wm_load_pointer: error loading pointer from file [%s]", + file_name); + return 1; } - g_memcpy(mask, fs->p, 128); /* mask */ - } - free_stream(fs); - return 0; + + g_file_read(fd, fs->data, 8192); + g_file_close(fd); + in_uint8s(fs, 6); + in_uint8(fs, w); + in_uint8(fs, h); + in_uint8s(fs, 2); + in_uint16_le(fs, *x); + in_uint16_le(fs, *y); + in_uint8s(fs, 22); + in_uint8(fs, bpp); + in_uint8s(fs, 25); + + if (w == 32 && h == 32) + { + if (bpp == 1) + { + in_uint8a(fs, palette, 8); + + for (i = 0; i < 32; i++) + { + for (j = 0; j < 32; j++) + { + pixel = palette[xrdp_wm_get_pixel(fs->p, j, i, 32, 1)]; + *data = pixel; + data++; + *data = pixel >> 8; + data++; + *data = pixel >> 16; + data++; + } + } + + in_uint8s(fs, 128); + } + else if (bpp == 4) + { + in_uint8a(fs, palette, 64); + + for (i = 0; i < 32; i++) + { + for (j = 0; j < 32; j++) + { + pixel = palette[xrdp_wm_get_pixel(fs->p, j, i, 32, 1)]; + *data = pixel; + data++; + *data = pixel >> 8; + data++; + *data = pixel >> 16; + data++; + } + } + + in_uint8s(fs, 512); + } + + g_memcpy(mask, fs->p, 128); /* mask */ + } + + free_stream(fs); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_wm_send_pointer(struct xrdp_wm* self, int cache_idx, - char* data, char* mask, int x, int y) +xrdp_wm_send_pointer(struct xrdp_wm *self, int cache_idx, + char *data, char *mask, int x, int y) { - return libxrdp_send_pointer(self->session, cache_idx, data, mask, x, y); + return libxrdp_send_pointer(self->session, cache_idx, data, mask, x, y); } /*****************************************************************************/ int APP_CC -xrdp_wm_set_pointer(struct xrdp_wm* self, int cache_idx) +xrdp_wm_set_pointer(struct xrdp_wm *self, int cache_idx) { - return libxrdp_set_pointer(self->session, cache_idx); + return libxrdp_set_pointer(self->session, cache_idx); } /*****************************************************************************/ /* convert hex string to int */ unsigned int xrdp_wm_htoi (const char *ptr) { - unsigned int value = 0; - char ch = *ptr; + unsigned int value = 0; + char ch = *ptr; - while (ch == ' ' || ch == '\t') - ch = *(++ptr); + while (ch == ' ' || ch == '\t') + { + ch = *(++ptr); + } - for (;;) - { - if (ch >= '0' && ch <= '9') - value = (value << 4) + (ch - '0'); - else if (ch >= 'A' && ch <= 'F') - value = (value << 4) + (ch - 'A' + 10); - else if (ch >= 'a' && ch <= 'f') - value = (value << 4) + (ch - 'a' + 10); - else - return value; - ch = *(++ptr); - } + for (;;) + { + if (ch >= '0' && ch <= '9') + { + value = (value << 4) + (ch - '0'); + } + else if (ch >= 'A' && ch <= 'F') + { + value = (value << 4) + (ch - 'A' + 10); + } + else if (ch >= 'a' && ch <= 'f') + { + value = (value << 4) + (ch - 'a' + 10); + } + else + { + return value; + } + + ch = *(++ptr); + } } /*****************************************************************************/ int APP_CC -xrdp_wm_load_static_colors_plus(struct xrdp_wm* self, char* autorun_name) +xrdp_wm_load_static_colors_plus(struct xrdp_wm *self, char *autorun_name) { - int bindex; - int gindex; - int rindex; + int bindex; + int gindex; + int rindex; - int fd; - int index; - char* val; - struct list* names; - struct list* values; - char cfg_file[256]; + int fd; + int index; + char *val; + struct list *names; + struct list *values; + char cfg_file[256]; - if (autorun_name != 0) - { - autorun_name[0] = 0; - } - - /* initialize with defaults */ - self->black = HCOLOR(self->screen->bpp,0x000000); - self->grey = HCOLOR(self->screen->bpp,0xc0c0c0); - self->dark_grey = HCOLOR(self->screen->bpp,0x808080); - self->blue = HCOLOR(self->screen->bpp,0x0000ff); - self->dark_blue = HCOLOR(self->screen->bpp,0x00007f); - self->white = HCOLOR(self->screen->bpp,0xffffff); - self->red = HCOLOR(self->screen->bpp,0xff0000); - self->green = HCOLOR(self->screen->bpp,0x00ff00); - self->background = HCOLOR(self->screen->bpp,0x000000); - - /* now load them from the globals in xrdp.ini if defined */ - g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); - fd = g_file_open(cfg_file); - if (fd > 0) - { - names = list_create(); - names->auto_free = 1; - values = list_create(); - values->auto_free = 1; - if (file_read_section(fd, "globals", names, values) == 0) + if (autorun_name != 0) { - for (index = 0; index < names->count; index++) - { - val = (char*)list_get_item(names, index); - if (val != 0) - { - if (g_strcasecmp(val, "black") == 0) - { - val = (char*)list_get_item(values, index); - self->black = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "grey") == 0) - { - val = (char*)list_get_item(values, index); - self->grey = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "dark_grey") == 0) - { - val = (char*)list_get_item(values, index); - self->dark_grey = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "blue") == 0) - { - val = (char*)list_get_item(values, index); - self->blue = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "dark_blue") == 0) - { - val = (char*)list_get_item(values, index); - self->dark_blue = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "white") == 0) - { - val = (char*)list_get_item(values, index); - self->white = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "red") == 0) - { - val = (char*)list_get_item(values, index); - self->red = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "green") == 0) - { - val = (char*)list_get_item(values, index); - self->green = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "background") == 0) - { - val = (char*)list_get_item(values, index); - self->background = HCOLOR(self->screen->bpp,xrdp_wm_htoi(val)); - } - else if (g_strcasecmp(val, "autorun") == 0) - { - val = (char*)list_get_item(values, index); - if (autorun_name != 0) - { - g_strncpy(autorun_name, val, 255); - } - } - else if (g_strcasecmp(val, "hidelogwindow") == 0) - { - val = (char*)list_get_item(values, index); - if ((g_strcasecmp(val, "yes") == 0) || - (g_strcasecmp(val, "1") == 0) || - (g_strcasecmp(val, "true") == 0)) - { - self->hide_log_window = 1; - } - } - } - } + autorun_name[0] = 0; } - list_delete(names); - list_delete(values); - g_file_close(fd); - } - else - { - g_writeln("xrdp_wm_load_static_colors: Could not read xrdp.ini file %s", cfg_file); - } - if (self->screen->bpp == 8) - { - /* rgb332 */ - for (bindex = 0; bindex < 4; bindex++) + /* initialize with defaults */ + self->black = HCOLOR(self->screen->bpp, 0x000000); + self->grey = HCOLOR(self->screen->bpp, 0xc0c0c0); + self->dark_grey = HCOLOR(self->screen->bpp, 0x808080); + self->blue = HCOLOR(self->screen->bpp, 0x0000ff); + self->dark_blue = HCOLOR(self->screen->bpp, 0x00007f); + self->white = HCOLOR(self->screen->bpp, 0xffffff); + self->red = HCOLOR(self->screen->bpp, 0xff0000); + self->green = HCOLOR(self->screen->bpp, 0x00ff00); + self->background = HCOLOR(self->screen->bpp, 0x000000); + + /* now load them from the globals in xrdp.ini if defined */ + g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + fd = g_file_open(cfg_file); + + if (fd > 0) { - for (gindex = 0; gindex < 8; gindex++) - { - for (rindex = 0; rindex < 8; rindex++) + names = list_create(); + names->auto_free = 1; + values = list_create(); + values->auto_free = 1; + + if (file_read_section(fd, "globals", names, values) == 0) { - self->palette[(bindex << 6) | (gindex << 3) | rindex] = - (((rindex << 5) | (rindex << 2) | (rindex >> 1)) << 16) | - (((gindex << 5) | (gindex << 2) | (gindex >> 1)) << 8) | - ((bindex << 6) | (bindex << 4) | (bindex << 2) | (bindex)); + for (index = 0; index < names->count; index++) + { + val = (char *)list_get_item(names, index); + + if (val != 0) + { + if (g_strcasecmp(val, "black") == 0) + { + val = (char *)list_get_item(values, index); + self->black = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "grey") == 0) + { + val = (char *)list_get_item(values, index); + self->grey = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "dark_grey") == 0) + { + val = (char *)list_get_item(values, index); + self->dark_grey = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "blue") == 0) + { + val = (char *)list_get_item(values, index); + self->blue = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "dark_blue") == 0) + { + val = (char *)list_get_item(values, index); + self->dark_blue = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "white") == 0) + { + val = (char *)list_get_item(values, index); + self->white = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "red") == 0) + { + val = (char *)list_get_item(values, index); + self->red = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "green") == 0) + { + val = (char *)list_get_item(values, index); + self->green = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "background") == 0) + { + val = (char *)list_get_item(values, index); + self->background = HCOLOR(self->screen->bpp, xrdp_wm_htoi(val)); + } + else if (g_strcasecmp(val, "autorun") == 0) + { + val = (char *)list_get_item(values, index); + + if (autorun_name != 0) + { + g_strncpy(autorun_name, val, 255); + } + } + else if (g_strcasecmp(val, "hidelogwindow") == 0) + { + val = (char *)list_get_item(values, index); + + if ((g_strcasecmp(val, "yes") == 0) || + (g_strcasecmp(val, "1") == 0) || + (g_strcasecmp(val, "true") == 0)) + { + self->hide_log_window = 1; + } + } + } + } } - } + + list_delete(names); + list_delete(values); + g_file_close(fd); } - xrdp_wm_send_palette(self); - } - return 0; + else + { + g_writeln("xrdp_wm_load_static_colors: Could not read xrdp.ini file %s", cfg_file); + } + + if (self->screen->bpp == 8) + { + /* rgb332 */ + for (bindex = 0; bindex < 4; bindex++) + { + for (gindex = 0; gindex < 8; gindex++) + { + for (rindex = 0; rindex < 8; rindex++) + { + self->palette[(bindex << 6) | (gindex << 3) | rindex] = + (((rindex << 5) | (rindex << 2) | (rindex >> 1)) << 16) | + (((gindex << 5) | (gindex << 2) | (gindex >> 1)) << 8) | + ((bindex << 6) | (bindex << 4) | (bindex << 2) | (bindex)); + } + } + } + + xrdp_wm_send_palette(self); + } + + return 0; } /*****************************************************************************/ /* returns error */ int APP_CC -xrdp_wm_load_static_pointers(struct xrdp_wm* self) +xrdp_wm_load_static_pointers(struct xrdp_wm *self) { - struct xrdp_pointer_item pointer_item; - char file_path[256]; + struct xrdp_pointer_item pointer_item; + char file_path[256]; - DEBUG(("sending cursor")); - g_snprintf(file_path, 255, "%s/cursor1.cur", XRDP_SHARE_PATH); - g_memset(&pointer_item, 0, sizeof(pointer_item)); - xrdp_wm_load_pointer(self, file_path, pointer_item.data, - pointer_item.mask, &pointer_item.x, &pointer_item.y); - xrdp_cache_add_pointer_static(self->cache, &pointer_item, 1); - DEBUG(("sending cursor")); - g_snprintf(file_path, 255, "%s/cursor0.cur", XRDP_SHARE_PATH); - g_memset(&pointer_item, 0, sizeof(pointer_item)); - xrdp_wm_load_pointer(self, file_path, pointer_item.data, - pointer_item.mask, &pointer_item.x, &pointer_item.y); - xrdp_cache_add_pointer_static(self->cache, &pointer_item, 0); - return 0; + DEBUG(("sending cursor")); + g_snprintf(file_path, 255, "%s/cursor1.cur", XRDP_SHARE_PATH); + g_memset(&pointer_item, 0, sizeof(pointer_item)); + xrdp_wm_load_pointer(self, file_path, pointer_item.data, + pointer_item.mask, &pointer_item.x, &pointer_item.y); + xrdp_cache_add_pointer_static(self->cache, &pointer_item, 1); + DEBUG(("sending cursor")); + g_snprintf(file_path, 255, "%s/cursor0.cur", XRDP_SHARE_PATH); + g_memset(&pointer_item, 0, sizeof(pointer_item)); + xrdp_wm_load_pointer(self, file_path, pointer_item.data, + pointer_item.mask, &pointer_item.x, &pointer_item.y); + xrdp_cache_add_pointer_static(self->cache, &pointer_item, 0); + return 0; } /*****************************************************************************/ int APP_CC -xrdp_wm_init(struct xrdp_wm* self) +xrdp_wm_init(struct xrdp_wm *self) { - int fd; - int index; - struct list* names; - struct list* values; - char* q; - char* r; - char section_name[256]; - char cfg_file[256]; - char autorun_name[256]; + int fd; + int index; + struct list *names; + struct list *values; + char *q; + char *r; + char section_name[256]; + char cfg_file[256]; + char autorun_name[256]; - xrdp_wm_load_static_colors_plus(self, autorun_name); - xrdp_wm_load_static_pointers(self); - self->screen->bg_color = self->background; - if (self->session->client_info->rdp_autologin || (autorun_name[0] != 0)) - { - g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); - fd = g_file_open(cfg_file); /* xrdp.ini */ - if (fd > 0) + xrdp_wm_load_static_colors_plus(self, autorun_name); + xrdp_wm_load_static_pointers(self); + self->screen->bg_color = self->background; + + if (self->session->client_info->rdp_autologin || (autorun_name[0] != 0)) { - names = list_create(); - names->auto_free = 1; - values = list_create(); - values->auto_free = 1; - g_strncpy(section_name, self->session->client_info->domain, 255); - if (section_name[0] == 0) - { - if (autorun_name[0] == 0) + g_snprintf(cfg_file, 255, "%s/xrdp.ini", XRDP_CFG_PATH); + fd = g_file_open(cfg_file); /* xrdp.ini */ + + if (fd > 0) { - /* if no doamin is passed, and no autorun in xrdp.ini, - use the first item in the xrdp.ini - file thats not named 'globals' */ - file_read_sections(fd, names); - for (index = 0; index < names->count; index++) - { - q = (char*)list_get_item(names, index); - if (g_strncasecmp("globals", q, 8) != 0) + names = list_create(); + names->auto_free = 1; + values = list_create(); + values->auto_free = 1; + g_strncpy(section_name, self->session->client_info->domain, 255); + + if (section_name[0] == 0) { - g_strncpy(section_name, q, 255); - break; + if (autorun_name[0] == 0) + { + /* if no doamin is passed, and no autorun in xrdp.ini, + use the first item in the xrdp.ini + file thats not named 'globals' */ + file_read_sections(fd, names); + + for (index = 0; index < names->count; index++) + { + q = (char *)list_get_item(names, index); + + if (g_strncasecmp("globals", q, 8) != 0) + { + g_strncpy(section_name, q, 255); + break; + } + } + } + else + { + g_strncpy(section_name, autorun_name, 255); + } } - } + + list_clear(names); + + if (file_read_section(fd, section_name, names, values) == 0) + { + for (index = 0; index < names->count; index++) + { + q = (char *)list_get_item(names, index); + r = (char *)list_get_item(values, index); + + if (g_strncmp("password", q, 255) == 0) + { + /* if the password has been asked for by the module, use what the + client says. + if the password has been manually set in the config, use that + instead of what the client says. */ + if (g_strncmp("ask", r, 3) == 0) + { + r = self->session->client_info->password; + } + } + else if (g_strncmp("username", q, 255) == 0) + { + /* if the username has been asked for by the module, use what the + client says. + if the username has been manually set in the config, use that + instead of what the client says. */ + if (g_strncmp("ask", r, 3) == 0) + { + r = self->session->client_info->username; + } + } + + list_add_item(self->mm->login_names, (long)g_strdup(q)); + list_add_item(self->mm->login_values, (long)g_strdup(r)); + } + + xrdp_wm_set_login_mode(self, 2); + } + + list_delete(names); + list_delete(values); + g_file_close(fd); } else { - g_strncpy(section_name, autorun_name, 255); + g_writeln("xrdp_wm_init: Could not read xrdp.ini file %s", cfg_file); } - } - list_clear(names); - if (file_read_section(fd, section_name, names, values) == 0) - { - for (index = 0; index < names->count; index++) - { - q = (char*)list_get_item(names, index); - r = (char*)list_get_item(values, index); - if (g_strncmp("password", q, 255) == 0) - { - /* if the password has been asked for by the module, use what the - client says. - if the password has been manually set in the config, use that - instead of what the client says. */ - if (g_strncmp("ask", r, 3) == 0) - { - r = self->session->client_info->password; - } - } - else if (g_strncmp("username", q, 255) == 0) - { - /* if the username has been asked for by the module, use what the - client says. - if the username has been manually set in the config, use that - instead of what the client says. */ - if (g_strncmp("ask", r, 3) == 0) - { - r = self->session->client_info->username; - } - } - list_add_item(self->mm->login_names, (long)g_strdup(q)); - list_add_item(self->mm->login_values, (long)g_strdup(r)); - } - xrdp_wm_set_login_mode(self, 2); - } - list_delete(names); - list_delete(values); - g_file_close(fd); } else { - g_writeln("xrdp_wm_init: Could not read xrdp.ini file %s", cfg_file); + xrdp_login_wnd_create(self); + /* clear screen */ + xrdp_bitmap_invalidate(self->screen, 0); + xrdp_wm_set_focused(self, self->login_window); + xrdp_wm_set_login_mode(self, 1); } - } - else - { - xrdp_login_wnd_create(self); - /* clear screen */ - xrdp_bitmap_invalidate(self->screen, 0); - xrdp_wm_set_focused(self, self->login_window); - xrdp_wm_set_login_mode(self, 1); - } - return 0; + + return 0; } /*****************************************************************************/ /* returns the number for rects visible for an area relative to a drawable */ /* putting the rects in region */ int APP_CC -xrdp_wm_get_vis_region(struct xrdp_wm* self, struct xrdp_bitmap* bitmap, +xrdp_wm_get_vis_region(struct xrdp_wm *self, struct xrdp_bitmap *bitmap, int x, int y, int cx, int cy, - struct xrdp_region* region, int clip_children) + struct xrdp_region *region, int clip_children) { - int i; - struct xrdp_bitmap* p; - struct xrdp_rect a; - struct xrdp_rect b; + int i; + struct xrdp_bitmap *p; + struct xrdp_rect a; + struct xrdp_rect b; - /* area we are drawing */ - MAKERECT(a, bitmap->left + x, bitmap->top + y, cx, cy); - p = bitmap->parent; - while (p != 0) - { - RECTOFFSET(a, p->left, p->top); - p = p->parent; - } - a.left = MAX(self->screen->left, a.left); - a.top = MAX(self->screen->top, a.top); - a.right = MIN(self->screen->left + self->screen->width, a.right); - a.bottom = MIN(self->screen->top + self->screen->height, a.bottom); - xrdp_region_add_rect(region, &a); - if (clip_children) - { - /* loop through all windows in z order */ - for (i = 0; i < self->screen->child_list->count; i++) + /* area we are drawing */ + MAKERECT(a, bitmap->left + x, bitmap->top + y, cx, cy); + p = bitmap->parent; + + while (p != 0) { - p = (struct xrdp_bitmap*)list_get_item(self->screen->child_list, i); - if (p == bitmap || p == bitmap->parent) - { - return 0; - } - MAKERECT(b, p->left, p->top, p->width, p->height); - xrdp_region_subtract_rect(region, &b); + RECTOFFSET(a, p->left, p->top); + p = p->parent; } - } - return 0; + + a.left = MAX(self->screen->left, a.left); + a.top = MAX(self->screen->top, a.top); + a.right = MIN(self->screen->left + self->screen->width, a.right); + a.bottom = MIN(self->screen->top + self->screen->height, a.bottom); + xrdp_region_add_rect(region, &a); + + if (clip_children) + { + /* loop through all windows in z order */ + for (i = 0; i < self->screen->child_list->count; i++) + { + p = (struct xrdp_bitmap *)list_get_item(self->screen->child_list, i); + + if (p == bitmap || p == bitmap->parent) + { + return 0; + } + + MAKERECT(b, p->left, p->top, p->width, p->height); + xrdp_region_subtract_rect(region, &b); + } + } + + return 0; } /*****************************************************************************/ /* return the window at x, y on the screen */ -static struct xrdp_bitmap* APP_CC -xrdp_wm_at_pos(struct xrdp_bitmap* wnd, int x, int y, - struct xrdp_bitmap** wnd1) +static struct xrdp_bitmap *APP_CC +xrdp_wm_at_pos(struct xrdp_bitmap *wnd, int x, int y, + struct xrdp_bitmap **wnd1) { - int i; - struct xrdp_bitmap* p; - struct xrdp_bitmap* q; + int i; + struct xrdp_bitmap *p; + struct xrdp_bitmap *q; - /* loop through all windows in z order */ - for (i = 0; i < wnd->child_list->count; i++) - { - p = (struct xrdp_bitmap*)list_get_item(wnd->child_list, i); - if (x >= p->left && y >= p->top && x < p->left + p->width && - y < p->top + p->height) + /* loop through all windows in z order */ + for (i = 0; i < wnd->child_list->count; i++) { - if (wnd1 != 0) - { - *wnd1 = p; - } - q = xrdp_wm_at_pos(p, x - p->left, y - p->top, 0); - if (q == 0) - { - return p; - } - else - { - return q; - } + p = (struct xrdp_bitmap *)list_get_item(wnd->child_list, i); + + if (x >= p->left && y >= p->top && x < p->left + p->width && + y < p->top + p->height) + { + if (wnd1 != 0) + { + *wnd1 = p; + } + + q = xrdp_wm_at_pos(p, x - p->left, y - p->top, 0); + + if (q == 0) + { + return p; + } + else + { + return q; + } + } } - } - return 0; + + return 0; } /*****************************************************************************/ static int APP_CC -xrdp_wm_xor_pat(struct xrdp_wm* self, int x, int y, int cx, int cy) +xrdp_wm_xor_pat(struct xrdp_wm *self, int x, int y, int cx, int cy) { - self->painter->clip_children = 0; - self->painter->rop = 0x5a; - xrdp_painter_begin_update(self->painter); - self->painter->use_clip = 0; - self->painter->mix_mode = 1; - self->painter->brush.pattern[0] = 0xaa; - self->painter->brush.pattern[1] = 0x55; - self->painter->brush.pattern[2] = 0xaa; - self->painter->brush.pattern[3] = 0x55; - self->painter->brush.pattern[4] = 0xaa; - self->painter->brush.pattern[5] = 0x55; - self->painter->brush.pattern[6] = 0xaa; - self->painter->brush.pattern[7] = 0x55; - self->painter->brush.x_orgin = 0; - self->painter->brush.x_orgin = 0; - self->painter->brush.style = 3; - self->painter->bg_color = self->black; - self->painter->fg_color = self->white; - /* top */ - xrdp_painter_fill_rect(self->painter, self->screen, x, y, cx, 5); - /* bottom */ - xrdp_painter_fill_rect(self->painter, self->screen, x, y + (cy - 5), cx, 5); - /* left */ - xrdp_painter_fill_rect(self->painter, self->screen, x, y + 5, 5, cy - 10); - /* right */ - xrdp_painter_fill_rect(self->painter, self->screen, x + (cx - 5), y + 5, 5, - cy - 10); - xrdp_painter_end_update(self->painter); - self->painter->rop = 0xcc; - self->painter->clip_children = 1; - self->painter->mix_mode = 0; - return 0; + self->painter->clip_children = 0; + self->painter->rop = 0x5a; + xrdp_painter_begin_update(self->painter); + self->painter->use_clip = 0; + self->painter->mix_mode = 1; + self->painter->brush.pattern[0] = 0xaa; + self->painter->brush.pattern[1] = 0x55; + self->painter->brush.pattern[2] = 0xaa; + self->painter->brush.pattern[3] = 0x55; + self->painter->brush.pattern[4] = 0xaa; + self->painter->brush.pattern[5] = 0x55; + self->painter->brush.pattern[6] = 0xaa; + self->painter->brush.pattern[7] = 0x55; + self->painter->brush.x_orgin = 0; + self->painter->brush.x_orgin = 0; + self->painter->brush.style = 3; + self->painter->bg_color = self->black; + self->painter->fg_color = self->white; + /* top */ + xrdp_painter_fill_rect(self->painter, self->screen, x, y, cx, 5); + /* bottom */ + xrdp_painter_fill_rect(self->painter, self->screen, x, y + (cy - 5), cx, 5); + /* left */ + xrdp_painter_fill_rect(self->painter, self->screen, x, y + 5, 5, cy - 10); + /* right */ + xrdp_painter_fill_rect(self->painter, self->screen, x + (cx - 5), y + 5, 5, + cy - 10); + xrdp_painter_end_update(self->painter); + self->painter->rop = 0xcc; + self->painter->clip_children = 1; + self->painter->mix_mode = 0; + return 0; } /*****************************************************************************/ /* this don't are about nothing, just copy the bits */ /* no clipping rects, no windows in the way, nothing */ static int APP_CC -xrdp_wm_bitblt(struct xrdp_wm* self, - struct xrdp_bitmap* dst, int dx, int dy, - struct xrdp_bitmap* src, int sx, int sy, +xrdp_wm_bitblt(struct xrdp_wm *self, + struct xrdp_bitmap *dst, int dx, int dy, + struct xrdp_bitmap *src, int sx, int sy, int sw, int sh, int rop) { -// int i; -// int line_size; -// int Bpp; -// char* s; -// char* d; + // int i; + // int line_size; + // int Bpp; + // char* s; + // char* d; -// if (sw <= 0 || sh <= 0) -// return 0; - if (self->screen == dst && self->screen == src) - { /* send a screen blt */ -// Bpp = (dst->bpp + 7) / 8; -// line_size = sw * Bpp; -// s = src->data + (sy * src->width + sx) * Bpp; -// d = dst->data + (dy * dst->width + dx) * Bpp; -// for (i = 0; i < sh; i++) -// { -// //g_memcpy(d, s, line_size); -// s += src->width * Bpp; -// d += dst->width * Bpp; -// } - libxrdp_orders_init(self->session); - libxrdp_orders_screen_blt(self->session, dx, dy, sw, sh, sx, sy, rop, 0); - libxrdp_orders_send(self->session); - } - return 0; + // if (sw <= 0 || sh <= 0) + // return 0; + if (self->screen == dst && self->screen == src) + { + /* send a screen blt */ + // Bpp = (dst->bpp + 7) / 8; + // line_size = sw * Bpp; + // s = src->data + (sy * src->width + sx) * Bpp; + // d = dst->data + (dy * dst->width + dx) * Bpp; + // for (i = 0; i < sh; i++) + // { + // //g_memcpy(d, s, line_size); + // s += src->width * Bpp; + // d += dst->width * Bpp; + // } + libxrdp_orders_init(self->session); + libxrdp_orders_screen_blt(self->session, dx, dy, sw, sh, sx, sy, rop, 0); + libxrdp_orders_send(self->session); + } + + return 0; } /*****************************************************************************/ /* return true is rect is totaly exposed going in reverse z order */ /* from wnd up */ static int APP_CC -xrdp_wm_is_rect_vis(struct xrdp_wm* self, struct xrdp_bitmap* wnd, - struct xrdp_rect* rect) +xrdp_wm_is_rect_vis(struct xrdp_wm *self, struct xrdp_bitmap *wnd, + struct xrdp_rect *rect) { - struct xrdp_rect wnd_rect; - struct xrdp_bitmap* b; - int i;; + struct xrdp_rect wnd_rect; + struct xrdp_bitmap *b; + int i;; - /* if rect is part off screen */ - if (rect->left < 0) - { - return 0; - } - if (rect->top < 0) - { - return 0; - } - if (rect->right >= self->screen->width) - { - return 0; - } - if (rect->bottom >= self->screen->height) - { - return 0; - } - - i = list_index_of(self->screen->child_list, (long)wnd); - i--; - while (i >= 0) - { - b = (struct xrdp_bitmap*)list_get_item(self->screen->child_list, i); - MAKERECT(wnd_rect, b->left, b->top, b->width, b->height); - if (rect_intersect(rect, &wnd_rect, 0)) + /* if rect is part off screen */ + if (rect->left < 0) { - return 0; + return 0; } + + if (rect->top < 0) + { + return 0; + } + + if (rect->right >= self->screen->width) + { + return 0; + } + + if (rect->bottom >= self->screen->height) + { + return 0; + } + + i = list_index_of(self->screen->child_list, (long)wnd); i--; - } - return 1; + + while (i >= 0) + { + b = (struct xrdp_bitmap *)list_get_item(self->screen->child_list, i); + MAKERECT(wnd_rect, b->left, b->top, b->width, b->height); + + if (rect_intersect(rect, &wnd_rect, 0)) + { + return 0; + } + + i--; + } + + return 1; } /*****************************************************************************/ static int APP_CC -xrdp_wm_move_window(struct xrdp_wm* self, struct xrdp_bitmap* wnd, +xrdp_wm_move_window(struct xrdp_wm *self, struct xrdp_bitmap *wnd, int dx, int dy) { - struct xrdp_rect rect1; - struct xrdp_rect rect2; - struct xrdp_region* r; - int i; + struct xrdp_rect rect1; + struct xrdp_rect rect2; + struct xrdp_region *r; + int i; - MAKERECT(rect1, wnd->left, wnd->top, wnd->width, wnd->height); - if (xrdp_wm_is_rect_vis(self, wnd, &rect1)) - { - rect2 = rect1; - RECTOFFSET(rect2, dx, dy); - if (xrdp_wm_is_rect_vis(self, wnd, &rect2)) - { /* if both src and dst are unobscured, we can do a bitblt move */ - xrdp_wm_bitblt(self, self->screen, wnd->left + dx, wnd->top + dy, - self->screen, wnd->left, wnd->top, - wnd->width, wnd->height, 0xcc); - wnd->left += dx; - wnd->top += dy; - r = xrdp_region_create(self); - xrdp_region_add_rect(r, &rect1); - xrdp_region_subtract_rect(r, &rect2); - i = 0; - while (xrdp_region_get_rect(r, i, &rect1) == 0) - { - xrdp_bitmap_invalidate(self->screen, &rect1); - i++; - } - xrdp_region_delete(r); - return 0; - } - } - wnd->left += dx; - wnd->top += dy; - xrdp_bitmap_invalidate(self->screen, &rect1); - xrdp_bitmap_invalidate(wnd, 0); - return 0; -} + MAKERECT(rect1, wnd->left, wnd->top, wnd->width, wnd->height); -/*****************************************************************************/ -static int APP_CC -xrdp_wm_undraw_dragging_box(struct xrdp_wm* self, int do_begin_end) -{ - int boxx; - int boxy; + if (xrdp_wm_is_rect_vis(self, wnd, &rect1)) + { + rect2 = rect1; + RECTOFFSET(rect2, dx, dy); - if (self == 0) - { - return 0; - } - if (self->dragging) - { - if (self->draggingxorstate) - { - if (do_begin_end) - { - xrdp_painter_begin_update(self->painter); - } - boxx = self->draggingx - self->draggingdx; - boxy = self->draggingy - self->draggingdy; - xrdp_wm_xor_pat(self, boxx, boxy, self->draggingcx, self->draggingcy); - self->draggingxorstate = 0; - if (do_begin_end) - { - xrdp_painter_end_update(self->painter); - } - } - } - return 0; -} - -/*****************************************************************************/ -static int APP_CC -xrdp_wm_draw_dragging_box(struct xrdp_wm* self, int do_begin_end) -{ - int boxx; - int boxy; - - if (self == 0) - { - return 0; - } - if (self->dragging) - { - if (!self->draggingxorstate) - { - if (do_begin_end) - { - xrdp_painter_begin_update(self->painter); - } - boxx = self->draggingx - self->draggingdx; - boxy = self->draggingy - self->draggingdy; - xrdp_wm_xor_pat(self, boxx, boxy, self->draggingcx, self->draggingcy); - self->draggingxorstate = 1; - if (do_begin_end) - { - xrdp_painter_end_update(self->painter); - } - } - } - return 0; -} - -/*****************************************************************************/ -int APP_CC -xrdp_wm_mouse_move(struct xrdp_wm* self, int x, int y) -{ - struct xrdp_bitmap* b; - - if (self == 0) - { - return 0; - } - if (x < 0) - { - x = 0; - } - if (y < 0) - { - y = 0; - } - if (x >= self->screen->width) - { - x = self->screen->width; - } - if (y >= self->screen->height) - { - y = self->screen->height; - } - self->mouse_x = x; - self->mouse_y = y; - if (self->dragging) - { - xrdp_painter_begin_update(self->painter); - xrdp_wm_undraw_dragging_box(self, 0); - self->draggingx = x; - self->draggingy = y; - xrdp_wm_draw_dragging_box(self, 0); - xrdp_painter_end_update(self->painter); - return 0; - } - b = xrdp_wm_at_pos(self->screen, x, y, 0); - if (b == 0) /* if b is null, the movment must be over the screen */ - { - if (self->screen->pointer != self->current_pointer) - { - xrdp_wm_set_pointer(self, self->screen->pointer); - self->current_pointer = self->screen->pointer; - } - if (self->mm->mod != 0) /* if screen is mod controled */ - { - if (self->mm->mod->mod_event != 0) - { - self->mm->mod->mod_event(self->mm->mod, WM_MOUSEMOVE, x, y, 0, 0); - } - } - } - if (self->button_down != 0) - { - if (b == self->button_down && self->button_down->state == 0) - { - self->button_down->state = 1; - xrdp_bitmap_invalidate(self->button_down, 0); - } - else if (b != self->button_down) - { - self->button_down->state = 0; - xrdp_bitmap_invalidate(self->button_down, 0); - } - } - if (b != 0) - { - if (!self->dragging) - { - if (b->pointer != self->current_pointer) - { - xrdp_wm_set_pointer(self, b->pointer); - self->current_pointer = b->pointer; - } - xrdp_bitmap_def_proc(b, WM_MOUSEMOVE, - xrdp_bitmap_from_screenx(b, x), - xrdp_bitmap_from_screeny(b, y)); - if (self->button_down == 0) - { - if (b->notify != 0) + if (xrdp_wm_is_rect_vis(self, wnd, &rect2)) { - b->notify(b->owner, b, 2, x, y); - } - } - } - } - return 0; -} + /* if both src and dst are unobscured, we can do a bitblt move */ + xrdp_wm_bitblt(self, self->screen, wnd->left + dx, wnd->top + dy, + self->screen, wnd->left, wnd->top, + wnd->width, wnd->height, 0xcc); + wnd->left += dx; + wnd->top += dy; + r = xrdp_region_create(self); + xrdp_region_add_rect(r, &rect1); + xrdp_region_subtract_rect(r, &rect2); + i = 0; -/*****************************************************************************/ -static int APP_CC -xrdp_wm_clear_popup(struct xrdp_wm* self) -{ - int i; - struct xrdp_rect rect; - //struct xrdp_bitmap* b; - - //b = 0; - if (self->popup_wnd != 0) - { - //b = self->popup_wnd->popped_from; - i = list_index_of(self->screen->child_list, (long)self->popup_wnd); - list_remove_item(self->screen->child_list, i); - MAKERECT(rect, self->popup_wnd->left, self->popup_wnd->top, - self->popup_wnd->width, self->popup_wnd->height); - xrdp_bitmap_invalidate(self->screen, &rect); - xrdp_bitmap_delete(self->popup_wnd); - } - //xrdp_wm_set_focused(self, b->parent); - return 0; -} - -/*****************************************************************************/ -int APP_CC -xrdp_wm_mouse_click(struct xrdp_wm* self, int x, int y, int but, int down) -{ - struct xrdp_bitmap* control; - struct xrdp_bitmap* focus_out_control; - struct xrdp_bitmap* wnd; - int newx; - int newy; - int oldx; - int oldy; - - if (self == 0) - { - return 0; - } - if (x < 0) - { - x = 0; - } - if (y < 0) - { - y = 0; - } - if (x >= self->screen->width) - { - x = self->screen->width; - } - if (y >= self->screen->height) - { - y = self->screen->height; - } - if (self->dragging && but == 1 && !down && self->dragging_window != 0) - { /* if done dragging */ - self->draggingx = x; - self->draggingy = y; - newx = self->draggingx - self->draggingdx; - newy = self->draggingy - self->draggingdy; - oldx = self->dragging_window->left; - oldy = self->dragging_window->top; - /* draw xor box one more time */ - if (self->draggingxorstate) - { - xrdp_wm_xor_pat(self, newx, newy, self->draggingcx, self->draggingcy); - } - self->draggingxorstate = 0; - /* move screen to new location */ - xrdp_wm_move_window(self, self->dragging_window, newx - oldx, newy - oldy); - self->dragging_window = 0; - self->dragging = 0; - } - wnd = 0; - control = xrdp_wm_at_pos(self->screen, x, y, &wnd); - if (control == 0) - { - if (self->mm->mod != 0) /* if screen is mod controled */ - { - if (self->mm->mod->mod_event != 0) - { - if (but == 1 && down) - { - self->mm->mod->mod_event(self->mm->mod, WM_LBUTTONDOWN, x, y, 0, 0); - } - else if (but == 1 && !down) - { - self->mm->mod->mod_event(self->mm->mod, WM_LBUTTONUP, x, y, 0, 0); - } - if (but == 2 && down) - { - self->mm->mod->mod_event(self->mm->mod, WM_RBUTTONDOWN, x, y, 0, 0); - } - else if (but == 2 && !down) - { - self->mm->mod->mod_event(self->mm->mod, WM_RBUTTONUP, x, y, 0, 0); - } - if (but == 3 && down) - { - self->mm->mod->mod_event(self->mm->mod, WM_BUTTON3DOWN, x, y, 0, 0); - } - else if (but == 3 && !down) - { - self->mm->mod->mod_event(self->mm->mod, WM_BUTTON3UP, x, y, 0, 0); - } - if (but == 4) - { - self->mm->mod->mod_event(self->mm->mod, WM_BUTTON4DOWN, - self->mouse_x, self->mouse_y, 0, 0); - self->mm->mod->mod_event(self->mm->mod, WM_BUTTON4UP, - self->mouse_x, self->mouse_y, 0, 0); - } - if (but == 5) - { - self->mm->mod->mod_event(self->mm->mod, WM_BUTTON5DOWN, - self->mouse_x, self->mouse_y, 0, 0); - self->mm->mod->mod_event(self->mm->mod, WM_BUTTON5UP, - self->mouse_x, self->mouse_y, 0, 0); - } - } - } - } - if (self->popup_wnd != 0) - { - if (self->popup_wnd == control && !down) - { - xrdp_bitmap_def_proc(self->popup_wnd, WM_LBUTTONUP, x, y); - xrdp_wm_clear_popup(self); - self->button_down = 0; - return 0; - } - else if (self->popup_wnd != control && down) - { - xrdp_wm_clear_popup(self); - self->button_down = 0; - return 0; - } - } - if (control != 0) - { - if (wnd != 0) - { - if (wnd->modal_dialog != 0) /* if window has a modal dialog */ - { - return 0; - } - if (control == wnd) - { - } - else if (control->tab_stop) - { - focus_out_control = wnd->focused_control; - wnd->focused_control = control; - xrdp_bitmap_invalidate(focus_out_control, 0); - xrdp_bitmap_invalidate(control, 0); - } - } - if ((control->type == WND_TYPE_BUTTON || - control->type == WND_TYPE_COMBO) && - but == 1 && !down && self->button_down == control) - { /* if clicking up on a button that was clicked down */ - self->button_down = 0; - control->state = 0; - xrdp_bitmap_invalidate(control, 0); - if (control->parent != 0) - { - if (control->parent->notify != 0) - { - /* control can be invalid after this */ - control->parent->notify(control->owner, control, 1, x, y); - } - } - } - else if ((control->type == WND_TYPE_BUTTON || - control->type == WND_TYPE_COMBO) && - but == 1 && down) - { /* if clicking down on a button or combo */ - self->button_down = control; - control->state = 1; - xrdp_bitmap_invalidate(control, 0); - if (control->type == WND_TYPE_COMBO) - { - xrdp_wm_pu(self, control); - } - } - else if (but == 1 && down) - { - if (self->popup_wnd == 0) - { - xrdp_wm_set_focused(self, wnd); - if (control->type == WND_TYPE_WND && y < (control->top + 21)) - { /* if dragging */ - if (self->dragging) /* rarely happens */ - { - newx = self->draggingx - self->draggingdx; - newy = self->draggingy - self->draggingdy; - if (self->draggingxorstate) + while (xrdp_region_get_rect(r, i, &rect1) == 0) { - xrdp_wm_xor_pat(self, newx, newy, - self->draggingcx, self->draggingcy); + xrdp_bitmap_invalidate(self->screen, &rect1); + i++; } - self->draggingxorstate = 0; - } - self->dragging = 1; - self->dragging_window = control; - self->draggingorgx = control->left; - self->draggingorgy = control->top; - self->draggingx = x; - self->draggingy = y; - self->draggingdx = x - control->left; - self->draggingdy = y - control->top; - self->draggingcx = control->width; - self->draggingcy = control->height; + + xrdp_region_delete(r); + return 0; } - } } - } - else - { - xrdp_wm_set_focused(self, 0); - } - /* no matter what, mouse is up, reset button_down */ - if (but == 1 && !down && self->button_down != 0) - { - self->button_down = 0; - } - return 0; + + wnd->left += dx; + wnd->top += dy; + xrdp_bitmap_invalidate(self->screen, &rect1); + xrdp_bitmap_invalidate(wnd, 0); + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_wm_undraw_dragging_box(struct xrdp_wm *self, int do_begin_end) +{ + int boxx; + int boxy; + + if (self == 0) + { + return 0; + } + + if (self->dragging) + { + if (self->draggingxorstate) + { + if (do_begin_end) + { + xrdp_painter_begin_update(self->painter); + } + + boxx = self->draggingx - self->draggingdx; + boxy = self->draggingy - self->draggingdy; + xrdp_wm_xor_pat(self, boxx, boxy, self->draggingcx, self->draggingcy); + self->draggingxorstate = 0; + + if (do_begin_end) + { + xrdp_painter_end_update(self->painter); + } + } + } + + return 0; +} + +/*****************************************************************************/ +static int APP_CC +xrdp_wm_draw_dragging_box(struct xrdp_wm *self, int do_begin_end) +{ + int boxx; + int boxy; + + if (self == 0) + { + return 0; + } + + if (self->dragging) + { + if (!self->draggingxorstate) + { + if (do_begin_end) + { + xrdp_painter_begin_update(self->painter); + } + + boxx = self->draggingx - self->draggingdx; + boxy = self->draggingy - self->draggingdy; + xrdp_wm_xor_pat(self, boxx, boxy, self->draggingcx, self->draggingcy); + self->draggingxorstate = 1; + + if (do_begin_end) + { + xrdp_painter_end_update(self->painter); + } + } + } + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_wm_key(struct xrdp_wm* self, int device_flags, int scan_code) +xrdp_wm_mouse_move(struct xrdp_wm *self, int x, int y) { - int msg; - struct xrdp_key_info* ki; + struct xrdp_bitmap *b; + + if (self == 0) + { + return 0; + } + + if (x < 0) + { + x = 0; + } + + if (y < 0) + { + y = 0; + } + + if (x >= self->screen->width) + { + x = self->screen->width; + } + + if (y >= self->screen->height) + { + y = self->screen->height; + } + + self->mouse_x = x; + self->mouse_y = y; + + if (self->dragging) + { + xrdp_painter_begin_update(self->painter); + xrdp_wm_undraw_dragging_box(self, 0); + self->draggingx = x; + self->draggingy = y; + xrdp_wm_draw_dragging_box(self, 0); + xrdp_painter_end_update(self->painter); + return 0; + } + + b = xrdp_wm_at_pos(self->screen, x, y, 0); + + if (b == 0) /* if b is null, the movment must be over the screen */ + { + if (self->screen->pointer != self->current_pointer) + { + xrdp_wm_set_pointer(self, self->screen->pointer); + self->current_pointer = self->screen->pointer; + } + + if (self->mm->mod != 0) /* if screen is mod controled */ + { + if (self->mm->mod->mod_event != 0) + { + self->mm->mod->mod_event(self->mm->mod, WM_MOUSEMOVE, x, y, 0, 0); + } + } + } + + if (self->button_down != 0) + { + if (b == self->button_down && self->button_down->state == 0) + { + self->button_down->state = 1; + xrdp_bitmap_invalidate(self->button_down, 0); + } + else if (b != self->button_down) + { + self->button_down->state = 0; + xrdp_bitmap_invalidate(self->button_down, 0); + } + } + + if (b != 0) + { + if (!self->dragging) + { + if (b->pointer != self->current_pointer) + { + xrdp_wm_set_pointer(self, b->pointer); + self->current_pointer = b->pointer; + } + + xrdp_bitmap_def_proc(b, WM_MOUSEMOVE, + xrdp_bitmap_from_screenx(b, x), + xrdp_bitmap_from_screeny(b, y)); + + if (self->button_down == 0) + { + if (b->notify != 0) + { + b->notify(b->owner, b, 2, x, y); + } + } + } + } - /*g_printf("count %d\n", self->key_down_list->count);*/ - scan_code = scan_code % 128; - if (self->popup_wnd != 0) - { - xrdp_wm_clear_popup(self); return 0; - } - if (device_flags & KBD_FLAG_UP) /* 0x8000 */ - { - self->keys[scan_code] = 0; - msg = WM_KEYUP; - } - else /* key down */ - { - self->keys[scan_code] = 1 | device_flags; - msg = WM_KEYDOWN; - switch (scan_code) +} + +/*****************************************************************************/ +static int APP_CC +xrdp_wm_clear_popup(struct xrdp_wm *self) +{ + int i; + struct xrdp_rect rect; + //struct xrdp_bitmap* b; + + //b = 0; + if (self->popup_wnd != 0) { - case 58: - self->caps_lock = !self->caps_lock; - break; /* caps lock */ - case 69: - self->num_lock = !self->num_lock; - break; /* num lock */ - case 70: - self->scroll_lock = !self->scroll_lock; - break; /* scroll lock */ + //b = self->popup_wnd->popped_from; + i = list_index_of(self->screen->child_list, (long)self->popup_wnd); + list_remove_item(self->screen->child_list, i); + MAKERECT(rect, self->popup_wnd->left, self->popup_wnd->top, + self->popup_wnd->width, self->popup_wnd->height); + xrdp_bitmap_invalidate(self->screen, &rect); + xrdp_bitmap_delete(self->popup_wnd); } - } - if (self->mm->mod != 0) - { - if (self->mm->mod->mod_event != 0) + + //xrdp_wm_set_focused(self, b->parent); + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_wm_mouse_click(struct xrdp_wm *self, int x, int y, int but, int down) +{ + struct xrdp_bitmap *control; + struct xrdp_bitmap *focus_out_control; + struct xrdp_bitmap *wnd; + int newx; + int newy; + int oldx; + int oldy; + + if (self == 0) { - ki = get_key_info_from_scan_code - (device_flags, scan_code, self->keys, self->caps_lock, - self->num_lock, self->scroll_lock, - &(self->keymap)); - if (ki != 0) - { - self->mm->mod->mod_event(self->mm->mod, msg, ki->chr, ki->sym, - scan_code, device_flags); - } + return 0; } - } - else if (self->focused_window != 0) - { - xrdp_bitmap_def_proc(self->focused_window, - msg, scan_code, device_flags); - } - return 0; + + if (x < 0) + { + x = 0; + } + + if (y < 0) + { + y = 0; + } + + if (x >= self->screen->width) + { + x = self->screen->width; + } + + if (y >= self->screen->height) + { + y = self->screen->height; + } + + if (self->dragging && but == 1 && !down && self->dragging_window != 0) + { + /* if done dragging */ + self->draggingx = x; + self->draggingy = y; + newx = self->draggingx - self->draggingdx; + newy = self->draggingy - self->draggingdy; + oldx = self->dragging_window->left; + oldy = self->dragging_window->top; + + /* draw xor box one more time */ + if (self->draggingxorstate) + { + xrdp_wm_xor_pat(self, newx, newy, self->draggingcx, self->draggingcy); + } + + self->draggingxorstate = 0; + /* move screen to new location */ + xrdp_wm_move_window(self, self->dragging_window, newx - oldx, newy - oldy); + self->dragging_window = 0; + self->dragging = 0; + } + + wnd = 0; + control = xrdp_wm_at_pos(self->screen, x, y, &wnd); + + if (control == 0) + { + if (self->mm->mod != 0) /* if screen is mod controled */ + { + if (self->mm->mod->mod_event != 0) + { + if (but == 1 && down) + { + self->mm->mod->mod_event(self->mm->mod, WM_LBUTTONDOWN, x, y, 0, 0); + } + else if (but == 1 && !down) + { + self->mm->mod->mod_event(self->mm->mod, WM_LBUTTONUP, x, y, 0, 0); + } + + if (but == 2 && down) + { + self->mm->mod->mod_event(self->mm->mod, WM_RBUTTONDOWN, x, y, 0, 0); + } + else if (but == 2 && !down) + { + self->mm->mod->mod_event(self->mm->mod, WM_RBUTTONUP, x, y, 0, 0); + } + + if (but == 3 && down) + { + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON3DOWN, x, y, 0, 0); + } + else if (but == 3 && !down) + { + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON3UP, x, y, 0, 0); + } + + if (but == 4) + { + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON4DOWN, + self->mouse_x, self->mouse_y, 0, 0); + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON4UP, + self->mouse_x, self->mouse_y, 0, 0); + } + + if (but == 5) + { + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON5DOWN, + self->mouse_x, self->mouse_y, 0, 0); + self->mm->mod->mod_event(self->mm->mod, WM_BUTTON5UP, + self->mouse_x, self->mouse_y, 0, 0); + } + } + } + } + + if (self->popup_wnd != 0) + { + if (self->popup_wnd == control && !down) + { + xrdp_bitmap_def_proc(self->popup_wnd, WM_LBUTTONUP, x, y); + xrdp_wm_clear_popup(self); + self->button_down = 0; + return 0; + } + else if (self->popup_wnd != control && down) + { + xrdp_wm_clear_popup(self); + self->button_down = 0; + return 0; + } + } + + if (control != 0) + { + if (wnd != 0) + { + if (wnd->modal_dialog != 0) /* if window has a modal dialog */ + { + return 0; + } + + if (control == wnd) + { + } + else if (control->tab_stop) + { + focus_out_control = wnd->focused_control; + wnd->focused_control = control; + xrdp_bitmap_invalidate(focus_out_control, 0); + xrdp_bitmap_invalidate(control, 0); + } + } + + if ((control->type == WND_TYPE_BUTTON || + control->type == WND_TYPE_COMBO) && + but == 1 && !down && self->button_down == control) + { + /* if clicking up on a button that was clicked down */ + self->button_down = 0; + control->state = 0; + xrdp_bitmap_invalidate(control, 0); + + if (control->parent != 0) + { + if (control->parent->notify != 0) + { + /* control can be invalid after this */ + control->parent->notify(control->owner, control, 1, x, y); + } + } + } + else if ((control->type == WND_TYPE_BUTTON || + control->type == WND_TYPE_COMBO) && + but == 1 && down) + { + /* if clicking down on a button or combo */ + self->button_down = control; + control->state = 1; + xrdp_bitmap_invalidate(control, 0); + + if (control->type == WND_TYPE_COMBO) + { + xrdp_wm_pu(self, control); + } + } + else if (but == 1 && down) + { + if (self->popup_wnd == 0) + { + xrdp_wm_set_focused(self, wnd); + + if (control->type == WND_TYPE_WND && y < (control->top + 21)) + { + /* if dragging */ + if (self->dragging) /* rarely happens */ + { + newx = self->draggingx - self->draggingdx; + newy = self->draggingy - self->draggingdy; + + if (self->draggingxorstate) + { + xrdp_wm_xor_pat(self, newx, newy, + self->draggingcx, self->draggingcy); + } + + self->draggingxorstate = 0; + } + + self->dragging = 1; + self->dragging_window = control; + self->draggingorgx = control->left; + self->draggingorgy = control->top; + self->draggingx = x; + self->draggingy = y; + self->draggingdx = x - control->left; + self->draggingdy = y - control->top; + self->draggingcx = control->width; + self->draggingcy = control->height; + } + } + } + } + else + { + xrdp_wm_set_focused(self, 0); + } + + /* no matter what, mouse is up, reset button_down */ + if (but == 1 && !down && self->button_down != 0) + { + self->button_down = 0; + } + + return 0; +} + +/*****************************************************************************/ +int APP_CC +xrdp_wm_key(struct xrdp_wm *self, int device_flags, int scan_code) +{ + int msg; + struct xrdp_key_info *ki; + + /*g_printf("count %d\n", self->key_down_list->count);*/ + scan_code = scan_code % 128; + + if (self->popup_wnd != 0) + { + xrdp_wm_clear_popup(self); + return 0; + } + + if (device_flags & KBD_FLAG_UP) /* 0x8000 */ + { + self->keys[scan_code] = 0; + msg = WM_KEYUP; + } + else /* key down */ + { + self->keys[scan_code] = 1 | device_flags; + msg = WM_KEYDOWN; + + switch (scan_code) + { + case 58: + self->caps_lock = !self->caps_lock; + break; /* caps lock */ + case 69: + self->num_lock = !self->num_lock; + break; /* num lock */ + case 70: + self->scroll_lock = !self->scroll_lock; + break; /* scroll lock */ + } + } + + if (self->mm->mod != 0) + { + if (self->mm->mod->mod_event != 0) + { + ki = get_key_info_from_scan_code + (device_flags, scan_code, self->keys, self->caps_lock, + self->num_lock, self->scroll_lock, + &(self->keymap)); + + if (ki != 0) + { + self->mm->mod->mod_event(self->mm->mod, msg, ki->chr, ki->sym, + scan_code, device_flags); + } + } + } + else if (self->focused_window != 0) + { + xrdp_bitmap_def_proc(self->focused_window, + msg, scan_code, device_flags); + } + + return 0; } /*****************************************************************************/ /* happens when client gets focus and sends key modifier info */ int APP_CC -xrdp_wm_key_sync(struct xrdp_wm* self, int device_flags, int key_flags) +xrdp_wm_key_sync(struct xrdp_wm *self, int device_flags, int key_flags) { - self->num_lock = 0; - self->scroll_lock = 0; - self->caps_lock = 0; - if (key_flags & 1) - { - self->scroll_lock = 1; - } - if (key_flags & 2) - { - self->num_lock = 1; - } - if (key_flags & 4) - { - self->caps_lock = 1; - } - if (self->mm->mod != 0) - { - if (self->mm->mod->mod_event != 0) + self->num_lock = 0; + self->scroll_lock = 0; + self->caps_lock = 0; + + if (key_flags & 1) { - self->mm->mod->mod_event(self->mm->mod, 17, key_flags, device_flags, - key_flags, device_flags); + self->scroll_lock = 1; } - } - return 0; + + if (key_flags & 2) + { + self->num_lock = 1; + } + + if (key_flags & 4) + { + self->caps_lock = 1; + } + + if (self->mm->mod != 0) + { + if (self->mm->mod->mod_event != 0) + { + self->mm->mod->mod_event(self->mm->mod, 17, key_flags, device_flags, + key_flags, device_flags); + } + } + + return 0; } /*****************************************************************************/ int APP_CC -xrdp_wm_pu(struct xrdp_wm* self, struct xrdp_bitmap* control) +xrdp_wm_pu(struct xrdp_wm *self, struct xrdp_bitmap *control) { - int x; - int y; + int x; + int y; - if (self == 0) - { + if (self == 0) + { + return 0; + } + + if (control == 0) + { + return 0; + } + + self->popup_wnd = xrdp_bitmap_create(control->width, DEFAULT_WND_SPECIAL_H, + self->screen->bpp, + WND_TYPE_SPECIAL, self); + self->popup_wnd->popped_from = control; + self->popup_wnd->parent = self->screen; + self->popup_wnd->owner = self->screen; + x = xrdp_bitmap_to_screenx(control, 0); + y = xrdp_bitmap_to_screeny(control, 0); + self->popup_wnd->left = x; + self->popup_wnd->top = y + control->height; + self->popup_wnd->item_index = control->item_index; + list_insert_item(self->screen->child_list, 0, (long)self->popup_wnd); + xrdp_bitmap_invalidate(self->popup_wnd, 0); return 0; - } - if (control == 0) - { - return 0; - } - self->popup_wnd = xrdp_bitmap_create(control->width, DEFAULT_WND_SPECIAL_H, - self->screen->bpp, - WND_TYPE_SPECIAL, self); - self->popup_wnd->popped_from = control; - self->popup_wnd->parent = self->screen; - self->popup_wnd->owner = self->screen; - x = xrdp_bitmap_to_screenx(control, 0); - y = xrdp_bitmap_to_screeny(control, 0); - self->popup_wnd->left = x; - self->popup_wnd->top = y + control->height; - self->popup_wnd->item_index = control->item_index; - list_insert_item(self->screen->child_list, 0, (long)self->popup_wnd); - xrdp_bitmap_invalidate(self->popup_wnd, 0); - return 0; } /*****************************************************************************/ static int APP_CC -xrdp_wm_process_input_mouse(struct xrdp_wm* self, int device_flags, +xrdp_wm_process_input_mouse(struct xrdp_wm *self, int device_flags, int x, int y) { - DEBUG(("mouse event flags %4.4x x %d y %d", device_flags, x, y)); - if (device_flags & MOUSE_FLAG_MOVE) /* 0x0800 */ - { - xrdp_wm_mouse_move(self, x, y); - } - if (device_flags & MOUSE_FLAG_BUTTON1) /* 0x1000 */ - { - if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ + DEBUG(("mouse event flags %4.4x x %d y %d", device_flags, x, y)); + + if (device_flags & MOUSE_FLAG_MOVE) /* 0x0800 */ { - xrdp_wm_mouse_click(self, x, y, 1, 1); + xrdp_wm_mouse_move(self, x, y); } - else + + if (device_flags & MOUSE_FLAG_BUTTON1) /* 0x1000 */ { - xrdp_wm_mouse_click(self, x, y, 1, 0); + if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ + { + xrdp_wm_mouse_click(self, x, y, 1, 1); + } + else + { + xrdp_wm_mouse_click(self, x, y, 1, 0); + } } - } - if (device_flags & MOUSE_FLAG_BUTTON2) /* 0x2000 */ - { - if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ + + if (device_flags & MOUSE_FLAG_BUTTON2) /* 0x2000 */ { - xrdp_wm_mouse_click(self, x, y, 2, 1); + if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ + { + xrdp_wm_mouse_click(self, x, y, 2, 1); + } + else + { + xrdp_wm_mouse_click(self, x, y, 2, 0); + } } - else + + if (device_flags & MOUSE_FLAG_BUTTON3) /* 0x4000 */ { - xrdp_wm_mouse_click(self, x, y, 2, 0); + if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ + { + xrdp_wm_mouse_click(self, x, y, 3, 1); + } + else + { + xrdp_wm_mouse_click(self, x, y, 3, 0); + } } - } - if (device_flags & MOUSE_FLAG_BUTTON3) /* 0x4000 */ - { - if (device_flags & MOUSE_FLAG_DOWN) /* 0x8000 */ + + if (device_flags == MOUSE_FLAG_BUTTON4 || /* 0x0280 */ + device_flags == 0x0278) { - xrdp_wm_mouse_click(self, x, y, 3, 1); + xrdp_wm_mouse_click(self, 0, 0, 4, 0); } - else + + if (device_flags == MOUSE_FLAG_BUTTON5 || /* 0x0380 */ + device_flags == 0x0388) { - xrdp_wm_mouse_click(self, x, y, 3, 0); + xrdp_wm_mouse_click(self, 0, 0, 5, 0); } - } - if (device_flags == MOUSE_FLAG_BUTTON4 || /* 0x0280 */ - device_flags == 0x0278) - { - xrdp_wm_mouse_click(self, 0, 0, 4, 0); - } - if (device_flags == MOUSE_FLAG_BUTTON5 || /* 0x0380 */ - device_flags == 0x0388) - { - xrdp_wm_mouse_click(self, 0, 0, 5, 0); - } - return 0; + + return 0; } /******************************************************************************/ @@ -1386,34 +1531,37 @@ xrdp_wm_process_input_mouse(struct xrdp_wm* self, int device_flags, param3 = pointer to data param4 = total size */ static int APP_CC -xrdp_wm_process_channel_data(struct xrdp_wm* self, - tbus param1, tbus param2, - tbus param3, tbus param4) +xrdp_wm_process_channel_data(struct xrdp_wm *self, + tbus param1, tbus param2, + tbus param3, tbus param4) { - int rv; - int chanid ; - rv = 1; - if (self->mm->mod != 0) - { - chanid = LOWORD(param1); - if(is_channel_allowed(self, chanid)) + int rv; + int chanid ; + rv = 1; + + if (self->mm->mod != 0) { - if (self->mm->usechansrv) - { - rv = xrdp_mm_process_channel_data(self->mm, param1, param2, - param3, param4); - } - else - { - if (self->mm->mod->mod_event != 0) + chanid = LOWORD(param1); + + if (is_channel_allowed(self, chanid)) { - rv = self->mm->mod->mod_event(self->mm->mod, 0x5555, param1, param2, - param3, param4); + if (self->mm->usechansrv) + { + rv = xrdp_mm_process_channel_data(self->mm, param1, param2, + param3, param4); + } + else + { + if (self->mm->mod->mod_event != 0) + { + rv = self->mm->mod->mod_event(self->mm->mod, 0x5555, param1, param2, + param3, param4); + } + } } - } } - } - return rv; + + return rv; } /******************************************************************************/ @@ -1421,266 +1569,295 @@ xrdp_wm_process_channel_data(struct xrdp_wm* self, int DEFAULT_CC callback(long id, int msg, long param1, long param2, long param3, long param4) { - int rv; - struct xrdp_wm* wm; - struct xrdp_rect rect; + int rv; + struct xrdp_wm *wm; + struct xrdp_rect rect; - if (id == 0) /* "id" should be "struct xrdp_process*" as long */ - { - return 0; - } - wm = ((struct xrdp_process*)id)->wm; - if (wm == 0) - { - return 0; - } - rv = 0; - switch (msg) - { - case 0: /* RDP_INPUT_SYNCHRONIZE */ - rv = xrdp_wm_key_sync(wm, param3, param1); - break; - case 4: /* RDP_INPUT_SCANCODE */ - rv = xrdp_wm_key(wm, param3, param1); - break; - case 0x8001: /* RDP_INPUT_MOUSE */ - rv = xrdp_wm_process_input_mouse(wm, param3, param1, param2); - break; - case 0x4444: /* invalidate, this is not from RDP_DATA_PDU_INPUT */ - /* like the rest, its from RDP_PDU_DATA with code 33 */ - /* its the rdp client asking for a screen update */ - MAKERECT(rect, param1, param2, param3, param4); - rv = xrdp_bitmap_invalidate(wm->screen, &rect); - break; - case 0x5555: /* called from xrdp_channel.c, channel data has come in, + if (id == 0) /* "id" should be "struct xrdp_process*" as long */ + { + return 0; + } + + wm = ((struct xrdp_process *)id)->wm; + + if (wm == 0) + { + return 0; + } + + rv = 0; + + switch (msg) + { + case 0: /* RDP_INPUT_SYNCHRONIZE */ + rv = xrdp_wm_key_sync(wm, param3, param1); + break; + case 4: /* RDP_INPUT_SCANCODE */ + rv = xrdp_wm_key(wm, param3, param1); + break; + case 0x8001: /* RDP_INPUT_MOUSE */ + rv = xrdp_wm_process_input_mouse(wm, param3, param1, param2); + break; + case 0x4444: /* invalidate, this is not from RDP_DATA_PDU_INPUT */ + /* like the rest, its from RDP_PDU_DATA with code 33 */ + /* its the rdp client asking for a screen update */ + MAKERECT(rect, param1, param2, param3, param4); + rv = xrdp_bitmap_invalidate(wm->screen, &rect); + break; + case 0x5555: /* called from xrdp_channel.c, channel data has come in, pass it to module if there is one */ - rv = xrdp_wm_process_channel_data(wm, param1, param2, param3, param4); - break; - } - return rv; + rv = xrdp_wm_process_channel_data(wm, param1, param2, param3, param4); + break; + } + + return rv; } /******************************************************************************/ /* returns error */ /* this gets called when there is nothing on any socket */ static int APP_CC -xrdp_wm_login_mode_changed(struct xrdp_wm* self) +xrdp_wm_login_mode_changed(struct xrdp_wm *self) { - if (self == 0) - { + if (self == 0) + { + return 0; + } + + if (self->login_mode == 0) + { + /* this is the inital state of the login window */ + xrdp_wm_set_login_mode(self, 1); /* put the wm in login mode */ + list_clear(self->log); + xrdp_wm_delete_all_childs(self); + self->dragging = 0; + xrdp_wm_init(self); + } + else if (self->login_mode == 2) + { + if (xrdp_mm_connect(self->mm) == 0) + { + xrdp_wm_set_login_mode(self, 3); /* put the wm in connected mode */ + xrdp_wm_delete_all_childs(self); + self->dragging = 0; + } + else + { + /* we do nothing on connect error so far */ + } + } + else if (self->login_mode == 10) + { + xrdp_wm_delete_all_childs(self); + self->dragging = 0; + xrdp_wm_set_login_mode(self, 11); + } + return 0; - } - if (self->login_mode == 0) - { - /* this is the inital state of the login window */ - xrdp_wm_set_login_mode(self, 1); /* put the wm in login mode */ - list_clear(self->log); - xrdp_wm_delete_all_childs(self); - self->dragging = 0; - xrdp_wm_init(self); - } - else if (self->login_mode == 2) - { - if (xrdp_mm_connect(self->mm) == 0) - { - xrdp_wm_set_login_mode(self, 3); /* put the wm in connected mode */ - xrdp_wm_delete_all_childs(self); - self->dragging = 0; - } - else - { - /* we do nothing on connect error so far */ - } - } - else if (self->login_mode == 10) - { - xrdp_wm_delete_all_childs(self); - self->dragging = 0; - xrdp_wm_set_login_mode(self, 11); - } - return 0; } /*****************************************************************************/ /* this is the log windows nofity function */ static int DEFAULT_CC -xrdp_wm_log_wnd_notify(struct xrdp_bitmap* wnd, - struct xrdp_bitmap* sender, +xrdp_wm_log_wnd_notify(struct xrdp_bitmap *wnd, + struct xrdp_bitmap *sender, int msg, long param1, long param2) { - struct xrdp_painter* painter; - struct xrdp_wm* wm; - struct xrdp_rect rect; - int index; - char* text; + struct xrdp_painter *painter; + struct xrdp_wm *wm; + struct xrdp_rect rect; + int index; + char *text; - if (wnd == 0) - { - return 0; - } - if (sender == 0) - { - return 0; - } - if (wnd->owner == 0) - { - return 0; - } - wm = wnd->wm; - if (msg == 1) /* click */ - { - if (sender->id == 1) /* ok button */ + if (wnd == 0) { - /* close the log window */ - MAKERECT(rect, wnd->left, wnd->top, wnd->width, wnd->height); - xrdp_bitmap_delete(wnd); - xrdp_bitmap_invalidate(wm->screen, &rect); - /* if module is gone, reset the session when ok is clicked */ - if (wm->mm->mod_handle == 0) - { - /* make sure autologin is off */ - wm->session->client_info->rdp_autologin = 0; - xrdp_wm_set_login_mode(wm, 0); /* reset session */ - } + return 0; } - } - else if (msg == WM_PAINT) /* 3 */ - { - painter = (struct xrdp_painter*)param1; - if (painter != 0) + + if (sender == 0) { - painter->fg_color = wnd->wm->black; - for (index = 0; index < wnd->wm->log->count; index++) - { - text = (char*)list_get_item(wnd->wm->log, index); - xrdp_painter_draw_text(painter, wnd, 10, 30 + index * 15, text); - } + return 0; } - } - return 0; + + if (wnd->owner == 0) + { + return 0; + } + + wm = wnd->wm; + + if (msg == 1) /* click */ + { + if (sender->id == 1) /* ok button */ + { + /* close the log window */ + MAKERECT(rect, wnd->left, wnd->top, wnd->width, wnd->height); + xrdp_bitmap_delete(wnd); + xrdp_bitmap_invalidate(wm->screen, &rect); + + /* if module is gone, reset the session when ok is clicked */ + if (wm->mm->mod_handle == 0) + { + /* make sure autologin is off */ + wm->session->client_info->rdp_autologin = 0; + xrdp_wm_set_login_mode(wm, 0); /* reset session */ + } + } + } + else if (msg == WM_PAINT) /* 3 */ + { + painter = (struct xrdp_painter *)param1; + + if (painter != 0) + { + painter->fg_color = wnd->wm->black; + + for (index = 0; index < wnd->wm->log->count; index++) + { + text = (char *)list_get_item(wnd->wm->log, index); + xrdp_painter_draw_text(painter, wnd, 10, 30 + index * 15, text); + } + } + } + + return 0; } - void add_string_to_logwindow(char *msg,struct list* log) - { - - char *new_part_message; - char *current_pointer = msg ; - int processedlen = 0; - do{ - new_part_message = g_strndup(current_pointer,LOG_WINDOW_CHAR_PER_LINE) ; - g_writeln(new_part_message); - list_add_item(log, (long)new_part_message); - processedlen = processedlen + g_strlen(new_part_message); - current_pointer = current_pointer + g_strlen(new_part_message) ; - }while((processedlenhide_log_window) - { - return 0; - } - add_string_to_logwindow(msg,self->log); - if (self->log_wnd == 0) - { - w = DEFAULT_WND_LOG_W; - h = DEFAULT_WND_LOG_H; - xoffset = 10; - yoffset = 10; - if (self->screen->width < w) + char *new_part_message; + char *current_pointer = msg ; + int processedlen = 0; + + do { - w = self->screen->width - 4; - xoffset = 2; + new_part_message = g_strndup(current_pointer, LOG_WINDOW_CHAR_PER_LINE) ; + g_writeln(new_part_message); + list_add_item(log, (long)new_part_message); + processedlen = processedlen + g_strlen(new_part_message); + current_pointer = current_pointer + g_strlen(new_part_message) ; } - if (self->screen->height < h) - { - h = self->screen->height - 4; - yoffset = 2; - } - /* log window */ - self->log_wnd = xrdp_bitmap_create(w, h, self->screen->bpp, - WND_TYPE_WND, self); - list_add_item(self->screen->child_list, (long)self->log_wnd); - self->log_wnd->parent = self->screen; - self->log_wnd->owner = self->screen; - self->log_wnd->bg_color = self->grey; - self->log_wnd->left = xoffset; - self->log_wnd->top = yoffset; - set_string(&(self->log_wnd->caption1), "Connection Log"); - /* ok button */ - but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); - list_insert_item(self->log_wnd->child_list, 0, (long)but); - but->parent = self->log_wnd; - but->owner = self->log_wnd; - but->left = (w - DEFAULT_BUTTON_W) - xoffset; - but->top = (h - DEFAULT_BUTTON_H) - yoffset; - but->id = 1; - but->tab_stop = 1; - set_string(&but->caption1, "OK"); - self->log_wnd->focused_control = but; - /* set notify function */ - self->log_wnd->notify = xrdp_wm_log_wnd_notify; - } - xrdp_wm_set_focused(self, self->log_wnd); - xrdp_bitmap_invalidate(self->log_wnd, 0); - g_sleep(100); - return 0; + while ((processedlen < g_strlen(msg)) && (processedlen < DEFAULT_STRING_LEN)); } /*****************************************************************************/ int APP_CC -xrdp_wm_get_wait_objs(struct xrdp_wm* self, tbus* robjs, int* rc, - tbus* wobjs, int* wc, int* timeout) +xrdp_wm_log_msg(struct xrdp_wm *self, char *msg) { - int i; + struct xrdp_bitmap *but; + int w; + int h; + int xoffset; + int yoffset; - if (self == 0) - { + if (self->hide_log_window) + { + return 0; + } + + add_string_to_logwindow(msg, self->log); + + if (self->log_wnd == 0) + { + w = DEFAULT_WND_LOG_W; + h = DEFAULT_WND_LOG_H; + xoffset = 10; + yoffset = 10; + + if (self->screen->width < w) + { + w = self->screen->width - 4; + xoffset = 2; + } + + if (self->screen->height < h) + { + h = self->screen->height - 4; + yoffset = 2; + } + + /* log window */ + self->log_wnd = xrdp_bitmap_create(w, h, self->screen->bpp, + WND_TYPE_WND, self); + list_add_item(self->screen->child_list, (long)self->log_wnd); + self->log_wnd->parent = self->screen; + self->log_wnd->owner = self->screen; + self->log_wnd->bg_color = self->grey; + self->log_wnd->left = xoffset; + self->log_wnd->top = yoffset; + set_string(&(self->log_wnd->caption1), "Connection Log"); + /* ok button */ + but = xrdp_bitmap_create(DEFAULT_BUTTON_W, DEFAULT_BUTTON_H, self->screen->bpp, WND_TYPE_BUTTON, self); + list_insert_item(self->log_wnd->child_list, 0, (long)but); + but->parent = self->log_wnd; + but->owner = self->log_wnd; + but->left = (w - DEFAULT_BUTTON_W) - xoffset; + but->top = (h - DEFAULT_BUTTON_H) - yoffset; + but->id = 1; + but->tab_stop = 1; + set_string(&but->caption1, "OK"); + self->log_wnd->focused_control = but; + /* set notify function */ + self->log_wnd->notify = xrdp_wm_log_wnd_notify; + } + + xrdp_wm_set_focused(self, self->log_wnd); + xrdp_bitmap_invalidate(self->log_wnd, 0); + g_sleep(100); return 0; - } - i = *rc; - robjs[i++] = self->login_mode_event; - *rc = i; - return xrdp_mm_get_wait_objs(self->mm, robjs, rc, wobjs, wc, timeout); +} + +/*****************************************************************************/ +int APP_CC +xrdp_wm_get_wait_objs(struct xrdp_wm *self, tbus *robjs, int *rc, + tbus *wobjs, int *wc, int *timeout) +{ + int i; + + if (self == 0) + { + return 0; + } + + i = *rc; + robjs[i++] = self->login_mode_event; + *rc = i; + return xrdp_mm_get_wait_objs(self->mm, robjs, rc, wobjs, wc, timeout); } /******************************************************************************/ int APP_CC -xrdp_wm_check_wait_objs(struct xrdp_wm* self) +xrdp_wm_check_wait_objs(struct xrdp_wm *self) { - int rv; + int rv; - if (self == 0) - { - return 0; - } - rv = 0; - if (g_is_wait_obj_set(self->login_mode_event)) - { - g_reset_wait_obj(self->login_mode_event); - xrdp_wm_login_mode_changed(self); - } - if (rv == 0) - { - rv = xrdp_mm_check_wait_objs(self->mm); - } - return rv; + if (self == 0) + { + return 0; + } + + rv = 0; + + if (g_is_wait_obj_set(self->login_mode_event)) + { + g_reset_wait_obj(self->login_mode_event); + xrdp_wm_login_mode_changed(self); + } + + if (rv == 0) + { + rv = xrdp_mm_check_wait_objs(self->mm); + } + + return rv; } /*****************************************************************************/ int APP_CC -xrdp_wm_set_login_mode(struct xrdp_wm* self, int login_mode) +xrdp_wm_set_login_mode(struct xrdp_wm *self, int login_mode) { - self->login_mode = login_mode; - g_set_wait_obj(self->login_mode_event); - return 0; + self->login_mode = login_mode; + g_set_wait_obj(self->login_mode_event); + return 0; } diff --git a/xrdp/xrdpwin.c b/xrdp/xrdpwin.c index 849f7112..ed6fa4c5 100644 --- a/xrdp/xrdpwin.c +++ b/xrdp/xrdpwin.c @@ -1,31 +1,29 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2012 - - main program - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * main program + */ #if defined(_WIN32) #include #endif #include "xrdp.h" -static struct xrdp_listen* g_listen = 0; +static struct xrdp_listen *g_listen = 0; static long g_threadid = 0; /* main threadid */ #if defined(_WIN32) @@ -48,113 +46,120 @@ long APP_CC g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1, long sync_param2) { - long sync_result; - int sync_command; + long sync_result; + int sync_command; - if (tc_threadid_equal(tc_get_threadid(), g_threadid)) - { - /* this is the main thread, call the function directly */ - sync_result = sync_func(sync_param1, sync_param2); - } - else - { - tc_mutex_lock(g_sync1_mutex); - tc_mutex_lock(g_sync_mutex); - g_sync_param1 = sync_param1; - g_sync_param2 = sync_param2; - g_sync_func = sync_func; - g_sync_command = 100; - tc_mutex_unlock(g_sync_mutex); - g_set_wait_obj(g_sync_event); - do + if (tc_threadid_equal(tc_get_threadid(), g_threadid)) { - g_sleep(100); - tc_mutex_lock(g_sync_mutex); - sync_command = g_sync_command; - sync_result = g_sync_result; - tc_mutex_unlock(g_sync_mutex); + /* this is the main thread, call the function directly */ + sync_result = sync_func(sync_param1, sync_param2); } - while (sync_command != 0); - tc_mutex_unlock(g_sync1_mutex); - } - return sync_result; + else + { + tc_mutex_lock(g_sync1_mutex); + tc_mutex_lock(g_sync_mutex); + g_sync_param1 = sync_param1; + g_sync_param2 = sync_param2; + g_sync_func = sync_func; + g_sync_command = 100; + tc_mutex_unlock(g_sync_mutex); + g_set_wait_obj(g_sync_event); + + do + { + g_sleep(100); + tc_mutex_lock(g_sync_mutex); + sync_command = g_sync_command; + sync_result = g_sync_result; + tc_mutex_unlock(g_sync_mutex); + } + while (sync_command != 0); + + tc_mutex_unlock(g_sync1_mutex); + } + + return sync_result; } /*****************************************************************************/ void DEFAULT_CC xrdp_shutdown(int sig) { - tbus threadid; + tbus threadid; - threadid = tc_get_threadid(); - g_writeln("shutting down"); - g_writeln("signal %d threadid %p", sig, threadid); - if (!g_is_wait_obj_set(g_term_event)) - { - g_set_wait_obj(g_term_event); - } + threadid = tc_get_threadid(); + g_writeln("shutting down"); + g_writeln("signal %d threadid %p", sig, threadid); + + if (!g_is_wait_obj_set(g_term_event)) + { + g_set_wait_obj(g_term_event); + } } /*****************************************************************************/ int APP_CC g_is_term(void) { - return g_is_wait_obj_set(g_term_event); + return g_is_wait_obj_set(g_term_event); } /*****************************************************************************/ void APP_CC g_set_term(int in_val) { - if (in_val) - { - g_set_wait_obj(g_term_event); - } - else - { - g_reset_wait_obj(g_term_event); - } + if (in_val) + { + g_set_wait_obj(g_term_event); + } + else + { + g_reset_wait_obj(g_term_event); + } } /*****************************************************************************/ tbus APP_CC g_get_term_event(void) { - return g_term_event; + return g_term_event; } /*****************************************************************************/ tbus APP_CC g_get_sync_event(void) { - return g_sync_event; + return g_sync_event; } /*****************************************************************************/ void DEFAULT_CC pipe_sig(int sig_num) { - /* do nothing */ - g_writeln("got SIGPIPE(%d)", sig_num); + /* do nothing */ + g_writeln("got SIGPIPE(%d)", sig_num); } /*****************************************************************************/ void APP_CC g_process_waiting_function(void) { - tc_mutex_lock(g_sync_mutex); - if (g_sync_command != 0) - { - if (g_sync_func != 0) + tc_mutex_lock(g_sync_mutex); + + if (g_sync_command != 0) { - if (g_sync_command == 100) - { - g_sync_result = g_sync_func(g_sync_param1, g_sync_param2); - } + if (g_sync_func != 0) + { + if (g_sync_command == 100) + { + g_sync_result = g_sync_func(g_sync_param1, g_sync_param2); + } + } + + g_sync_command = 0; } - g_sync_command = 0; - } - tc_mutex_unlock(g_sync_mutex); + + tc_mutex_unlock(g_sync_mutex); } /* win32 service control functions */ @@ -164,444 +169,484 @@ g_process_waiting_function(void) VOID WINAPI MyHandler(DWORD fdwControl) { - if (g_ssh == 0) - { - return; - } - if (fdwControl == SERVICE_CONTROL_STOP) - { - g_service_status.dwCurrentState = SERVICE_STOP_PENDING; - g_set_term(1); - } - else if (fdwControl == SERVICE_CONTROL_PAUSE) - { - /* shouldn't happen */ - } - else if (fdwControl == SERVICE_CONTROL_CONTINUE) - { - /* shouldn't happen */ - } - else if (fdwControl == SERVICE_CONTROL_INTERROGATE) - { - } - else if (fdwControl == SERVICE_CONTROL_SHUTDOWN) - { - g_service_status.dwCurrentState = SERVICE_STOP_PENDING; - g_set_term(1); - } - SetServiceStatus(g_ssh, &g_service_status); + if (g_ssh == 0) + { + return; + } + + if (fdwControl == SERVICE_CONTROL_STOP) + { + g_service_status.dwCurrentState = SERVICE_STOP_PENDING; + g_set_term(1); + } + else if (fdwControl == SERVICE_CONTROL_PAUSE) + { + /* shouldn't happen */ + } + else if (fdwControl == SERVICE_CONTROL_CONTINUE) + { + /* shouldn't happen */ + } + else if (fdwControl == SERVICE_CONTROL_INTERROGATE) + { + } + else if (fdwControl == SERVICE_CONTROL_SHUTDOWN) + { + g_service_status.dwCurrentState = SERVICE_STOP_PENDING; + g_set_term(1); + } + + SetServiceStatus(g_ssh, &g_service_status); } /*****************************************************************************/ static void DEFAULT_CC -log_event(HANDLE han, char* msg) +log_event(HANDLE han, char *msg) { - ReportEvent(han, EVENTLOG_INFORMATION_TYPE, 0, 0, 0, 1, 0, &msg, 0); + ReportEvent(han, EVENTLOG_INFORMATION_TYPE, 0, 0, 0, 1, 0, &msg, 0); } /*****************************************************************************/ VOID WINAPI -MyServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) +MyServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) { - WSADATA w; - char text[256]; - int pid; - //HANDLE event_han; -// int fd; -// char text[256]; + WSADATA w; + char text[256]; + int pid; + //HANDLE event_han; + // int fd; + // char text[256]; -// fd = g_file_open("c:\\temp\\xrdp\\log.txt"); -// g_file_write(fd, "hi\r\n", 4); - //event_han = RegisterEventSource(0, "xrdp"); - //log_event(event_han, "hi xrdp log"); - g_threadid = tc_get_threadid(); - g_set_current_dir("c:\\temp\\xrdp"); - g_listen = 0; - WSAStartup(2, &w); - g_sync_mutex = tc_mutex_create(); - g_sync1_mutex = tc_mutex_create(); - pid = g_getpid(); - g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); - g_term_event = g_create_wait_obj(text); - g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); - g_sync_event = g_create_wait_obj(text); - g_memset(&g_service_status, 0, sizeof(SERVICE_STATUS)); - g_service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - g_service_status.dwCurrentState = SERVICE_RUNNING; - g_service_status.dwControlsAccepted = SERVICE_CONTROL_INTERROGATE | - SERVICE_ACCEPT_STOP | - SERVICE_ACCEPT_SHUTDOWN; - g_service_status.dwWin32ExitCode = NO_ERROR; - g_service_status.dwServiceSpecificExitCode = 0; - g_service_status.dwCheckPoint = 0; - g_service_status.dwWaitHint = 0; -// g_sprintf(text, "calling RegisterServiceCtrlHandler\r\n"); -// g_file_write(fd, text, g_strlen(text)); - g_ssh = RegisterServiceCtrlHandler("xrdp", MyHandler); - if (g_ssh != 0) - { -// g_sprintf(text, "ok\r\n"); -// g_file_write(fd, text, g_strlen(text)); - SetServiceStatus(g_ssh, &g_service_status); - g_listen = xrdp_listen_create(); - xrdp_listen_main_loop(g_listen); - g_sleep(100); - g_service_status.dwCurrentState = SERVICE_STOPPED; - SetServiceStatus(g_ssh, &g_service_status); - } - else - { - //g_sprintf(text, "RegisterServiceCtrlHandler failed\r\n"); - //g_file_write(fd, text, g_strlen(text)); - } - xrdp_listen_delete(g_listen); - tc_mutex_delete(g_sync_mutex); - tc_mutex_delete(g_sync1_mutex); - g_destroy_wait_obj(g_term_event); - g_destroy_wait_obj(g_sync_event); - WSACleanup(); - //CloseHandle(event_han); + // fd = g_file_open("c:\\temp\\xrdp\\log.txt"); + // g_file_write(fd, "hi\r\n", 4); + //event_han = RegisterEventSource(0, "xrdp"); + //log_event(event_han, "hi xrdp log"); + g_threadid = tc_get_threadid(); + g_set_current_dir("c:\\temp\\xrdp"); + g_listen = 0; + WSAStartup(2, &w); + g_sync_mutex = tc_mutex_create(); + g_sync1_mutex = tc_mutex_create(); + pid = g_getpid(); + g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); + g_term_event = g_create_wait_obj(text); + g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); + g_sync_event = g_create_wait_obj(text); + g_memset(&g_service_status, 0, sizeof(SERVICE_STATUS)); + g_service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + g_service_status.dwCurrentState = SERVICE_RUNNING; + g_service_status.dwControlsAccepted = SERVICE_CONTROL_INTERROGATE | + SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN; + g_service_status.dwWin32ExitCode = NO_ERROR; + g_service_status.dwServiceSpecificExitCode = 0; + g_service_status.dwCheckPoint = 0; + g_service_status.dwWaitHint = 0; + // g_sprintf(text, "calling RegisterServiceCtrlHandler\r\n"); + // g_file_write(fd, text, g_strlen(text)); + g_ssh = RegisterServiceCtrlHandler("xrdp", MyHandler); + + if (g_ssh != 0) + { + // g_sprintf(text, "ok\r\n"); + // g_file_write(fd, text, g_strlen(text)); + SetServiceStatus(g_ssh, &g_service_status); + g_listen = xrdp_listen_create(); + xrdp_listen_main_loop(g_listen); + g_sleep(100); + g_service_status.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(g_ssh, &g_service_status); + } + else + { + //g_sprintf(text, "RegisterServiceCtrlHandler failed\r\n"); + //g_file_write(fd, text, g_strlen(text)); + } + + xrdp_listen_delete(g_listen); + tc_mutex_delete(g_sync_mutex); + tc_mutex_delete(g_sync1_mutex); + g_destroy_wait_obj(g_term_event); + g_destroy_wait_obj(g_sync_event); + WSACleanup(); + //CloseHandle(event_han); } #endif /*****************************************************************************/ int DEFAULT_CC -main(int argc, char** argv) +main(int argc, char **argv) { - int test; - int host_be; + int test; + int host_be; #if defined(_WIN32) - WSADATA w; - SC_HANDLE sc_man; - SC_HANDLE sc_ser; - int run_as_service; - SERVICE_TABLE_ENTRY te[2]; + WSADATA w; + SC_HANDLE sc_man; + SC_HANDLE sc_ser; + int run_as_service; + SERVICE_TABLE_ENTRY te[2]; #else - int pid; - int fd; - int no_daemon; - char text[256]; - char pid_file[256]; + int pid; + int fd; + int no_daemon; + char text[256]; + char pid_file[256]; #endif - g_init(); - ssl_init(); - /* check compiled endian with actual endian */ - test = 1; - host_be = !((int)(*(unsigned char*)(&test))); + g_init(); + ssl_init(); + /* check compiled endian with actual endian */ + test = 1; + host_be = !((int)(*(unsigned char *)(&test))); #if defined(B_ENDIAN) - if (!host_be) + + if (!host_be) #endif #if defined(L_ENDIAN) - if (host_be) + if (host_be) #endif - { - g_writeln("endian wrong, edit arch.h"); - return 0; - } - /* check long, int and void* sizes */ - if (sizeof(int) != 4) - { - g_writeln("unusable int size, must be 4"); - return 0; - } - if (sizeof(long) != sizeof(void*)) - { - g_writeln("long size must match void* size"); - return 0; - } - if (sizeof(long) != 4 && sizeof(long) != 8) - { - g_writeln("unusable long size, must be 4 or 8"); - return 0; - } - if (sizeof(tui64) != 8) - { - g_writeln("unusable tui64 size, must be 8"); - return 0; - } -#if defined(_WIN32) - run_as_service = 1; - if (argc == 2) - { - if (g_strncasecmp(argv[1], "-help", 255) == 0 || - g_strncasecmp(argv[1], "--help", 255) == 0 || - g_strncasecmp(argv[1], "-h", 255) == 0) - { - g_writeln(""); - g_writeln("xrdp: A Remote Desktop Protocol server."); - g_writeln("Copyright (C) Jay Sorg 2004-2011"); - g_writeln("See http://xrdp.sourceforge.net for more information."); - g_writeln(""); - g_writeln("Usage: xrdp [options]"); - g_writeln(" -h: show help"); - g_writeln(" -install: install service"); - g_writeln(" -remove: remove service"); - g_writeln(""); - g_exit(0); - } - else if (g_strncasecmp(argv[1], "-install", 255) == 0 || - g_strncasecmp(argv[1], "--install", 255) == 0 || - g_strncasecmp(argv[1], "-i", 255) == 0) - { - /* open service manager */ - sc_man = OpenSCManager(0, 0, GENERIC_WRITE); - if (sc_man == 0) - { - g_writeln("error OpenSCManager, do you have rights?"); - g_exit(0); - } - /* check if service is allready installed */ - sc_ser = OpenService(sc_man, "xrdp", SERVICE_ALL_ACCESS); - if (sc_ser == 0) - { - /* install service */ - CreateService(sc_man, "xrdp", "xrdp", SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, - SERVICE_ERROR_IGNORE, "c:\\temp\\xrdp\\xrdp.exe", - 0, 0, 0, 0, 0); - - } - else - { - g_writeln("error service is allready installed"); - CloseServiceHandle(sc_ser); - CloseServiceHandle(sc_man); - g_exit(0); - } - CloseServiceHandle(sc_man); - g_exit(0); - } - else if (g_strncasecmp(argv[1], "-remove", 255) == 0 || - g_strncasecmp(argv[1], "--remove", 255) == 0 || - g_strncasecmp(argv[1], "-r", 255) == 0) - { - /* open service manager */ - sc_man = OpenSCManager(0, 0, GENERIC_WRITE); - if (sc_man == 0) - { - g_writeln("error OpenSCManager, do you have rights?"); - g_exit(0); - } - /* check if service is allready installed */ - sc_ser = OpenService(sc_man, "xrdp", SERVICE_ALL_ACCESS); - if (sc_ser == 0) - { - g_writeln("error service is not installed"); - CloseServiceHandle(sc_man); - g_exit(0); - } - DeleteService(sc_ser); - CloseServiceHandle(sc_man); - g_exit(0); - } - else - { - g_writeln("Unknown Parameter"); - g_writeln("xrdp -h for help"); - g_writeln(""); - g_exit(0); - } - } - else if (argc > 1) - { - g_writeln("Unknown Parameter"); - g_writeln("xrdp -h for help"); - g_writeln(""); - g_exit(0); - } - if (run_as_service) - { - g_memset(&te, 0, sizeof(te)); - te[0].lpServiceName = "xrdp"; - te[0].lpServiceProc = MyServiceMain; - StartServiceCtrlDispatcher(&te); - g_exit(0); - } - WSAStartup(2, &w); -#else /* _WIN32 */ - g_snprintf(pid_file, 255, "%s/xrdp.pid", XRDP_PID_PATH); - no_daemon = 0; - if (argc == 2) - { - if ((g_strncasecmp(argv[1], "-kill", 255) == 0) || - (g_strncasecmp(argv[1], "--kill", 255) == 0) || - (g_strncasecmp(argv[1], "-k", 255) == 0)) - { - g_writeln("stopping xrdp"); - /* read the xrdp.pid file */ - fd = -1; - if (g_file_exist(pid_file)) /* xrdp.pid */ - { - fd = g_file_open(pid_file); /* xrdp.pid */ - } - if (fd == -1) - { - g_writeln("problem opening to xrdp.pid"); - g_writeln("maybe its not running"); - } - else - { - g_memset(text, 0, 32); - g_file_read(fd, text, 31); - pid = g_atoi(text); - g_writeln("stopping process id %d", pid); - if (pid > 0) { - g_sigterm(pid); + g_writeln("endian wrong, edit arch.h"); + return 0; } - g_file_close(fd); - } - g_exit(0); - } - else if (g_strncasecmp(argv[1], "-nodaemon", 255) == 0 || - g_strncasecmp(argv[1], "--nodaemon", 255) == 0 || - g_strncasecmp(argv[1], "-nd", 255) == 0 || - g_strncasecmp(argv[1], "--nd", 255) == 0 || - g_strncasecmp(argv[1], "-ns", 255) == 0 || - g_strncasecmp(argv[1], "--ns", 255) == 0) - { - no_daemon = 1; - } - else if (g_strncasecmp(argv[1], "-help", 255) == 0 || - g_strncasecmp(argv[1], "--help", 255) == 0 || - g_strncasecmp(argv[1], "-h", 255) == 0) - { - g_writeln(""); - g_writeln("xrdp: A Remote Desktop Protocol server."); - g_writeln("Copyright (C) Jay Sorg 2004-2011"); - g_writeln("See http://xrdp.sourceforge.net for more information."); - g_writeln(""); - g_writeln("Usage: xrdp [options]"); - g_writeln(" -h: show help"); - g_writeln(" -nodaemon: don't fork into background"); - g_writeln(" -kill: shut down xrdp"); - g_writeln(""); - g_exit(0); - } - else if ((g_strncasecmp(argv[1], "-v", 255) == 0) || - (g_strncasecmp(argv[1], "--version", 255) == 0)) - { - g_writeln(""); - g_writeln("xrdp: A Remote Desktop Protocol server."); - g_writeln("Copyright (C) Jay Sorg 2004-2011"); - g_writeln("See http://xrdp.sourceforge.net for more information."); - g_writeln("Version %s",PACKAGE_VERSION); - g_writeln(""); - g_exit(0); - } - else - { - g_writeln("Unknown Parameter"); - g_writeln("xrdp -h for help"); - g_writeln(""); - g_exit(0); - } - } - else if (argc > 1) - { - g_writeln("Unknown Parameter"); - g_writeln("xrdp -h for help"); - g_writeln(""); - g_exit(0); - } - if (g_file_exist(pid_file)) /* xrdp.pid */ - { - g_writeln("It looks like xrdp is allready running,"); - g_writeln("if not delete the xrdp.pid file and try again"); - g_exit(0); - } - if (!no_daemon) - { - /* make sure we can write to pid file */ - fd = g_file_open(pid_file); /* xrdp.pid */ - if (fd == -1) - { - g_writeln("running in daemon mode with no access to pid files, quitting"); - g_exit(0); - } - if (g_file_write(fd, "0", 1) == -1) - { - g_writeln("running in daemon mode with no access to pid files, quitting"); - g_exit(0); - } - g_file_close(fd); - g_file_delete(pid_file); - } - if (!no_daemon) - { - /* start of daemonizing code */ - pid = g_fork(); - if (pid == -1) - { - g_writeln("problem forking"); - g_exit(1); - } - if (0 != pid) - { - g_writeln("process %d started ok", pid); - /* exit, this is the main process */ - g_exit(0); - } - g_sleep(1000); - g_file_close(0); - g_file_close(1); - g_file_close(2); - g_file_open("/dev/null"); - g_file_open("/dev/null"); - g_file_open("/dev/null"); - /* end of daemonizing code */ - } - if (!no_daemon) - { - /* write the pid to file */ - pid = g_getpid(); - fd = g_file_open(pid_file); /* xrdp.pid */ - if (fd == -1) - { - g_writeln("trying to write process id to xrdp.pid"); - g_writeln("problem opening xrdp.pid"); - g_writeln("maybe no rights"); - } - else - { - g_sprintf(text, "%d", pid); - g_file_write(fd, text, g_strlen(text)); - g_file_close(fd); - } - } -#endif - g_threadid = tc_get_threadid(); - g_listen = xrdp_listen_create(); - g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */ - g_signal_kill(xrdp_shutdown); /* SIGKILL */ - g_signal_pipe(pipe_sig); /* SIGPIPE */ - g_signal_terminate(xrdp_shutdown); /* SIGTERM */ - g_sync_mutex = tc_mutex_create(); - g_sync1_mutex = tc_mutex_create(); - pid = g_getpid(); - g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); - g_term_event = g_create_wait_obj(text); - g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); - g_sync_event = g_create_wait_obj(text); - if (g_term_event == 0) - { - g_writeln("error creating g_term_event"); - } - xrdp_listen_main_loop(g_listen); - xrdp_listen_delete(g_listen); - tc_mutex_delete(g_sync_mutex); - tc_mutex_delete(g_sync1_mutex); - g_delete_wait_obj(g_term_event); - g_delete_wait_obj(g_sync_event); -#if defined(_WIN32) - /* I don't think it ever gets here */ - /* when running in win32 app mode, control c exits right away */ - WSACleanup(); -#else - /* delete the xrdp.pid file */ - g_file_delete(pid_file); -#endif - return 0; -} + /* check long, int and void* sizes */ + if (sizeof(int) != 4) + { + g_writeln("unusable int size, must be 4"); + return 0; + } + + if (sizeof(long) != sizeof(void *)) + { + g_writeln("long size must match void* size"); + return 0; + } + + if (sizeof(long) != 4 && sizeof(long) != 8) + { + g_writeln("unusable long size, must be 4 or 8"); + return 0; + } + + if (sizeof(tui64) != 8) + { + g_writeln("unusable tui64 size, must be 8"); + return 0; + } + +#if defined(_WIN32) + run_as_service = 1; + + if (argc == 2) + { + if (g_strncasecmp(argv[1], "-help", 255) == 0 || + g_strncasecmp(argv[1], "--help", 255) == 0 || + g_strncasecmp(argv[1], "-h", 255) == 0) + { + g_writeln(""); + g_writeln("xrdp: A Remote Desktop Protocol server."); + g_writeln("Copyright (C) Jay Sorg 2004-2011"); + g_writeln("See http://xrdp.sourceforge.net for more information."); + g_writeln(""); + g_writeln("Usage: xrdp [options]"); + g_writeln(" -h: show help"); + g_writeln(" -install: install service"); + g_writeln(" -remove: remove service"); + g_writeln(""); + g_exit(0); + } + else if (g_strncasecmp(argv[1], "-install", 255) == 0 || + g_strncasecmp(argv[1], "--install", 255) == 0 || + g_strncasecmp(argv[1], "-i", 255) == 0) + { + /* open service manager */ + sc_man = OpenSCManager(0, 0, GENERIC_WRITE); + + if (sc_man == 0) + { + g_writeln("error OpenSCManager, do you have rights?"); + g_exit(0); + } + + /* check if service is allready installed */ + sc_ser = OpenService(sc_man, "xrdp", SERVICE_ALL_ACCESS); + + if (sc_ser == 0) + { + /* install service */ + CreateService(sc_man, "xrdp", "xrdp", SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, + SERVICE_ERROR_IGNORE, "c:\\temp\\xrdp\\xrdp.exe", + 0, 0, 0, 0, 0); + + } + else + { + g_writeln("error service is allready installed"); + CloseServiceHandle(sc_ser); + CloseServiceHandle(sc_man); + g_exit(0); + } + + CloseServiceHandle(sc_man); + g_exit(0); + } + else if (g_strncasecmp(argv[1], "-remove", 255) == 0 || + g_strncasecmp(argv[1], "--remove", 255) == 0 || + g_strncasecmp(argv[1], "-r", 255) == 0) + { + /* open service manager */ + sc_man = OpenSCManager(0, 0, GENERIC_WRITE); + + if (sc_man == 0) + { + g_writeln("error OpenSCManager, do you have rights?"); + g_exit(0); + } + + /* check if service is allready installed */ + sc_ser = OpenService(sc_man, "xrdp", SERVICE_ALL_ACCESS); + + if (sc_ser == 0) + { + g_writeln("error service is not installed"); + CloseServiceHandle(sc_man); + g_exit(0); + } + + DeleteService(sc_ser); + CloseServiceHandle(sc_man); + g_exit(0); + } + else + { + g_writeln("Unknown Parameter"); + g_writeln("xrdp -h for help"); + g_writeln(""); + g_exit(0); + } + } + else if (argc > 1) + { + g_writeln("Unknown Parameter"); + g_writeln("xrdp -h for help"); + g_writeln(""); + g_exit(0); + } + + if (run_as_service) + { + g_memset(&te, 0, sizeof(te)); + te[0].lpServiceName = "xrdp"; + te[0].lpServiceProc = MyServiceMain; + StartServiceCtrlDispatcher(&te); + g_exit(0); + } + + WSAStartup(2, &w); +#else /* _WIN32 */ + g_snprintf(pid_file, 255, "%s/xrdp.pid", XRDP_PID_PATH); + no_daemon = 0; + + if (argc == 2) + { + if ((g_strncasecmp(argv[1], "-kill", 255) == 0) || + (g_strncasecmp(argv[1], "--kill", 255) == 0) || + (g_strncasecmp(argv[1], "-k", 255) == 0)) + { + g_writeln("stopping xrdp"); + /* read the xrdp.pid file */ + fd = -1; + + if (g_file_exist(pid_file)) /* xrdp.pid */ + { + fd = g_file_open(pid_file); /* xrdp.pid */ + } + + if (fd == -1) + { + g_writeln("problem opening to xrdp.pid"); + g_writeln("maybe its not running"); + } + else + { + g_memset(text, 0, 32); + g_file_read(fd, text, 31); + pid = g_atoi(text); + g_writeln("stopping process id %d", pid); + + if (pid > 0) + { + g_sigterm(pid); + } + + g_file_close(fd); + } + + g_exit(0); + } + else if (g_strncasecmp(argv[1], "-nodaemon", 255) == 0 || + g_strncasecmp(argv[1], "--nodaemon", 255) == 0 || + g_strncasecmp(argv[1], "-nd", 255) == 0 || + g_strncasecmp(argv[1], "--nd", 255) == 0 || + g_strncasecmp(argv[1], "-ns", 255) == 0 || + g_strncasecmp(argv[1], "--ns", 255) == 0) + { + no_daemon = 1; + } + else if (g_strncasecmp(argv[1], "-help", 255) == 0 || + g_strncasecmp(argv[1], "--help", 255) == 0 || + g_strncasecmp(argv[1], "-h", 255) == 0) + { + g_writeln(""); + g_writeln("xrdp: A Remote Desktop Protocol server."); + g_writeln("Copyright (C) Jay Sorg 2004-2011"); + g_writeln("See http://xrdp.sourceforge.net for more information."); + g_writeln(""); + g_writeln("Usage: xrdp [options]"); + g_writeln(" -h: show help"); + g_writeln(" -nodaemon: don't fork into background"); + g_writeln(" -kill: shut down xrdp"); + g_writeln(""); + g_exit(0); + } + else if ((g_strncasecmp(argv[1], "-v", 255) == 0) || + (g_strncasecmp(argv[1], "--version", 255) == 0)) + { + g_writeln(""); + g_writeln("xrdp: A Remote Desktop Protocol server."); + g_writeln("Copyright (C) Jay Sorg 2004-2011"); + g_writeln("See http://xrdp.sourceforge.net for more information."); + g_writeln("Version %s", PACKAGE_VERSION); + g_writeln(""); + g_exit(0); + } + else + { + g_writeln("Unknown Parameter"); + g_writeln("xrdp -h for help"); + g_writeln(""); + g_exit(0); + } + } + else if (argc > 1) + { + g_writeln("Unknown Parameter"); + g_writeln("xrdp -h for help"); + g_writeln(""); + g_exit(0); + } + + if (g_file_exist(pid_file)) /* xrdp.pid */ + { + g_writeln("It looks like xrdp is allready running,"); + g_writeln("if not delete the xrdp.pid file and try again"); + g_exit(0); + } + + if (!no_daemon) + { + /* make sure we can write to pid file */ + fd = g_file_open(pid_file); /* xrdp.pid */ + + if (fd == -1) + { + g_writeln("running in daemon mode with no access to pid files, quitting"); + g_exit(0); + } + + if (g_file_write(fd, "0", 1) == -1) + { + g_writeln("running in daemon mode with no access to pid files, quitting"); + g_exit(0); + } + + g_file_close(fd); + g_file_delete(pid_file); + } + + if (!no_daemon) + { + /* start of daemonizing code */ + pid = g_fork(); + + if (pid == -1) + { + g_writeln("problem forking"); + g_exit(1); + } + + if (0 != pid) + { + g_writeln("process %d started ok", pid); + /* exit, this is the main process */ + g_exit(0); + } + + g_sleep(1000); + g_file_close(0); + g_file_close(1); + g_file_close(2); + g_file_open("/dev/null"); + g_file_open("/dev/null"); + g_file_open("/dev/null"); + /* end of daemonizing code */ + } + + if (!no_daemon) + { + /* write the pid to file */ + pid = g_getpid(); + fd = g_file_open(pid_file); /* xrdp.pid */ + + if (fd == -1) + { + g_writeln("trying to write process id to xrdp.pid"); + g_writeln("problem opening xrdp.pid"); + g_writeln("maybe no rights"); + } + else + { + g_sprintf(text, "%d", pid); + g_file_write(fd, text, g_strlen(text)); + g_file_close(fd); + } + } + +#endif + g_threadid = tc_get_threadid(); + g_listen = xrdp_listen_create(); + g_signal_user_interrupt(xrdp_shutdown); /* SIGINT */ + g_signal_kill(xrdp_shutdown); /* SIGKILL */ + g_signal_pipe(pipe_sig); /* SIGPIPE */ + g_signal_terminate(xrdp_shutdown); /* SIGTERM */ + g_sync_mutex = tc_mutex_create(); + g_sync1_mutex = tc_mutex_create(); + pid = g_getpid(); + g_snprintf(text, 255, "xrdp_%8.8x_main_term", pid); + g_term_event = g_create_wait_obj(text); + g_snprintf(text, 255, "xrdp_%8.8x_main_sync", pid); + g_sync_event = g_create_wait_obj(text); + + if (g_term_event == 0) + { + g_writeln("error creating g_term_event"); + } + + xrdp_listen_main_loop(g_listen); + xrdp_listen_delete(g_listen); + tc_mutex_delete(g_sync_mutex); + tc_mutex_delete(g_sync1_mutex); + g_delete_wait_obj(g_term_event); + g_delete_wait_obj(g_sync_event); +#if defined(_WIN32) + /* I don't think it ever gets here */ + /* when running in win32 app mode, control c exits right away */ + WSACleanup(); +#else + /* delete the xrdp.pid file */ + g_file_delete(pid_file); +#endif + return 0; +} diff --git a/xrdpapi/simple.c b/xrdpapi/simple.c index a2c0f875..7f309ab8 100644 --- a/xrdpapi/simple.c +++ b/xrdpapi/simple.c @@ -1,6 +1,24 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ - -// xrdp_chan_test.cpp : Basic test for virtual channel use. +/* + * Basic test for virtual channel use + */ // These headers are required for the windows terminal services calls. #include "xrdpapi.h" @@ -15,80 +33,87 @@ int main() { - // Initialize the data for send/receive - void* hFile; - char* data; - char* data1; - data = (char*)malloc(DSIZE); - data1 = (char*)malloc(DSIZE); - int ret; - void* vcFileHandlePtr = NULL; - memset(data, 0xca, DSIZE); - memset(data1, 0, DSIZE); - unsigned int written = 0; + // Initialize the data for send/receive + void *hFile; + char *data; + char *data1; + data = (char *)malloc(DSIZE); + data1 = (char *)malloc(DSIZE); + int ret; + void *vcFileHandlePtr = NULL; + memset(data, 0xca, DSIZE); + memset(data1, 0, DSIZE); + unsigned int written = 0; - // Open the skel channel in current session + // Open the skel channel in current session - //void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "skel", 0); - void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "TSMF", WTS_CHANNEL_OPTION_DYNAMIC); - ret = WTSVirtualChannelQuery(channel, WTSVirtualFileHandle, vcFileHandlePtr, &written); + //void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "skel", 0); + void *channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "TSMF", WTS_CHANNEL_OPTION_DYNAMIC); + ret = WTSVirtualChannelQuery(channel, WTSVirtualFileHandle, vcFileHandlePtr, &written); - // Write the data to the channel - ret = WTSVirtualChannelWrite(channel, data, DSIZE, &written); - if (!ret) - { + // Write the data to the channel + ret = WTSVirtualChannelWrite(channel, data, DSIZE, &written); - long err = errno; - printf("error 1 0x%8.8x\n", err); - usleep(100000); - return 1; - } - else - { - printf("Sent bytes!\n"); - } - if (written != DSIZE) - { - long err = errno; - printf("error 2 0x%8.8x\n", err); - usleep(100000); - return 1; - } - else - { - printf("Read bytes!\n"); - } - ret = WTSVirtualChannelRead(channel, 100, data1, DSIZE, &written); - if (!ret) - { - long err = errno; - printf("error 3 0x%8.8x\n", err); - usleep(100000); - return 1; - } - if (written != DSIZE) - { - long err = errno; - printf("error 4 0x%8.8x\n", err); - usleep(100000); - return 1; - } - else - { - printf("Read bytes!\n"); - } - ret = WTSVirtualChannelClose(channel); - if (memcmp(data, data1, DSIZE) == 0) - { - } - else - { - printf("error data no match\n"); - return 1; - } + if (!ret) + { - printf("Done!\n"); + long err = errno; + printf("error 1 0x%8.8x\n", err); + usleep(100000); + return 1; + } + else + { + printf("Sent bytes!\n"); + } - usleep(100000); - return 0; + if (written != DSIZE) + { + long err = errno; + printf("error 2 0x%8.8x\n", err); + usleep(100000); + return 1; + } + else + { + printf("Read bytes!\n"); + } + + ret = WTSVirtualChannelRead(channel, 100, data1, DSIZE, &written); + + if (!ret) + { + long err = errno; + printf("error 3 0x%8.8x\n", err); + usleep(100000); + return 1; + } + + if (written != DSIZE) + { + long err = errno; + printf("error 4 0x%8.8x\n", err); + usleep(100000); + return 1; + } + else + { + printf("Read bytes!\n"); + } + + ret = WTSVirtualChannelClose(channel); + + if (memcmp(data, data1, DSIZE) == 0) + { + } + else + { + printf("error data no match\n"); + return 1; + } + + printf("Done!\n"); + + usleep(100000); + return 0; } diff --git a/xrdpapi/xrdpapi.c b/xrdpapi/xrdpapi.c index 694b3800..85a13a8e 100644 --- a/xrdpapi/xrdpapi.c +++ b/xrdpapi/xrdpapi.c @@ -21,9 +21,9 @@ #define LOG_LEVEL 1 #define LLOG(_level, _args) \ - do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) + do { if (_level < LOG_LEVEL) { ErrorF _args ; } } while (0) #define LLOGLN(_level, _args) \ - do { if (_level < LOG_LEVEL) { printf _args ; printf("\n"); } } while (0) + do { if (_level < LOG_LEVEL) { printf _args ; printf("\n"); } } while (0) #include #include @@ -40,344 +40,382 @@ struct wts_obj { - int fd; - int status; - char name[8]; - char dname[128]; - int display_num; - int flags; + int fd; + int status; + char name[8]; + char dname[128]; + int display_num; + int flags; }; /*****************************************************************************/ static int -get_display_num_from_display(char* display_text) +get_display_num_from_display(char *display_text) { - int index; - int mode; - int host_index; - int disp_index; - int scre_index; - char host[256]; - char disp[256]; - char scre[256]; + int index; + int mode; + int host_index; + int disp_index; + int scre_index; + char host[256]; + char disp[256]; + char scre[256]; - index = 0; - host_index = 0; - disp_index = 0; - scre_index = 0; - mode = 0; - while (display_text[index] != 0) - { - if (display_text[index] == ':') + index = 0; + host_index = 0; + disp_index = 0; + scre_index = 0; + mode = 0; + + while (display_text[index] != 0) { - mode = 1; + if (display_text[index] == ':') + { + mode = 1; + } + else if (display_text[index] == '.') + { + mode = 2; + } + else if (mode == 0) + { + host[host_index] = display_text[index]; + host_index++; + } + else if (mode == 1) + { + disp[disp_index] = display_text[index]; + disp_index++; + } + else if (mode == 2) + { + scre[scre_index] = display_text[index]; + scre_index++; + } + + index++; } - else if (display_text[index] == '.') - { - mode = 2; - } - else if (mode == 0) - { - host[host_index] = display_text[index]; - host_index++; - } - else if (mode == 1) - { - disp[disp_index] = display_text[index]; - disp_index++; - } - else if (mode == 2) - { - scre[scre_index] = display_text[index]; - scre_index++; - } - index++; - } - host[host_index] = 0; - disp[disp_index] = 0; - scre[scre_index] = 0; - return atoi(disp); + + host[host_index] = 0; + disp[disp_index] = 0; + scre[scre_index] = 0; + return atoi(disp); } /*****************************************************************************/ -void* -WTSVirtualChannelOpen(void* hServer, unsigned int SessionId, - const char* pVirtualName) +void * +WTSVirtualChannelOpen(void *hServer, unsigned int SessionId, + const char *pVirtualName) { - if (hServer != WTS_CURRENT_SERVER_HANDLE) - { - return 0; - } - return WTSVirtualChannelOpenEx(SessionId, pVirtualName, 0); + if (hServer != WTS_CURRENT_SERVER_HANDLE) + { + return 0; + } + + return WTSVirtualChannelOpenEx(SessionId, pVirtualName, 0); } /*****************************************************************************/ static int can_send(int sck, int millis) { - struct timeval time; - fd_set wfds; - int select_rv; + struct timeval time; + fd_set wfds; + int select_rv; - FD_ZERO(&wfds); - FD_SET(sck, &wfds); - time.tv_sec = millis / 1000; - time.tv_usec = (millis * 1000) % 1000000; - select_rv = select(sck + 1, 0, &wfds, 0, &time); - if (select_rv > 0) - { - return 1; - } - return 0; + FD_ZERO(&wfds); + FD_SET(sck, &wfds); + time.tv_sec = millis / 1000; + time.tv_usec = (millis * 1000) % 1000000; + select_rv = select(sck + 1, 0, &wfds, 0, &time); + + if (select_rv > 0) + { + return 1; + } + + return 0; } /*****************************************************************************/ static int can_recv(int sck, int millis) { - struct timeval time; - fd_set rfds; - int select_rv; + struct timeval time; + fd_set rfds; + int select_rv; - FD_ZERO(&rfds); - FD_SET(sck, &rfds); - time.tv_sec = millis / 1000; - time.tv_usec = (millis * 1000) % 1000000; - select_rv = select(sck + 1, &rfds, 0, 0, &time); - if (select_rv > 0) - { - return 1; - } - return 0; + FD_ZERO(&rfds); + FD_SET(sck, &rfds); + time.tv_sec = millis / 1000; + time.tv_usec = (millis * 1000) % 1000000; + select_rv = select(sck + 1, &rfds, 0, 0, &time); + + if (select_rv > 0) + { + return 1; + } + + return 0; } /*****************************************************************************/ static int -send_init(struct wts_obj* wts) +send_init(struct wts_obj *wts) { - char initmsg[64]; + char initmsg[64]; - memset(initmsg, 0, 64); - strncpy(initmsg, wts->name, 8); - initmsg[16] = (wts->flags >> 0) & 0xff; - initmsg[17] = (wts->flags >> 8) & 0xff; - initmsg[18] = (wts->flags >> 16) & 0xff; - initmsg[19] = (wts->flags >> 24) & 0xff; - LLOGLN(10, ("send_init: sending %s", initmsg)); - if (!can_send(wts->fd, 500)) - { - return 1; - } - if (send(wts->fd, initmsg, 64, 0) != 64) - { - return 1; - } - LLOGLN(10, ("send_init: send ok!")); - return 0; + memset(initmsg, 0, 64); + strncpy(initmsg, wts->name, 8); + initmsg[16] = (wts->flags >> 0) & 0xff; + initmsg[17] = (wts->flags >> 8) & 0xff; + initmsg[18] = (wts->flags >> 16) & 0xff; + initmsg[19] = (wts->flags >> 24) & 0xff; + LLOGLN(10, ("send_init: sending %s", initmsg)); + + if (!can_send(wts->fd, 500)) + { + return 1; + } + + if (send(wts->fd, initmsg, 64, 0) != 64) + { + return 1; + } + + LLOGLN(10, ("send_init: send ok!")); + return 0; } /*****************************************************************************/ -void* +void * WTSVirtualChannelOpenEx(unsigned int SessionId, - const char* pVirtualName, + const char *pVirtualName, unsigned int flags) { - struct wts_obj* wts; - char* display_text; - struct sockaddr_un s; - int bytes; - unsigned long llong; + struct wts_obj *wts; + char *display_text; + struct sockaddr_un s; + int bytes; + unsigned long llong; - if (SessionId != WTS_CURRENT_SESSION) - { - LLOGLN(0, ("WTSVirtualChannelOpenEx: SessionId bad")); - return 0; - } - wts = (struct wts_obj*)malloc(sizeof(struct wts_obj)); - memset(wts, 0, sizeof(struct wts_obj)); - wts->fd = -1; - wts->flags = flags; - display_text = getenv("DISPLAY"); - if (display_text != 0) - { - wts->display_num = get_display_num_from_display(display_text); - } - if (wts->display_num > 0) - { - wts->fd = socket(AF_UNIX, SOCK_STREAM, 0); - /* set non blocking */ - llong = fcntl(wts->fd, F_GETFL); - llong = llong | O_NONBLOCK; - fcntl(wts->fd, F_SETFL, llong); - /* connect to session chansrv */ - memset(&s, 0, sizeof(struct sockaddr_un)); - s.sun_family = AF_UNIX; - bytes = sizeof(s.sun_path); - snprintf(s.sun_path, bytes - 1, "/tmp/.xrdp/xrdpapi_%d", wts->display_num); - s.sun_path[bytes - 1] = 0; - bytes = sizeof(struct sockaddr_un); - if (connect(wts->fd, (struct sockaddr*)&s, bytes) == 0) + if (SessionId != WTS_CURRENT_SESSION) { - LLOGLN(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName)); - strncpy(wts->name, pVirtualName, 8); - /* wait for connection to complete and send init */ - if (send_init(wts) == 0) - { - /* all ok */ - wts->status = 1; - } + LLOGLN(0, ("WTSVirtualChannelOpenEx: SessionId bad")); + return 0; } - } - else - { - LLOGLN(0, ("WTSVirtualChannelOpenEx: display is 0")); - } - return wts; + + wts = (struct wts_obj *)malloc(sizeof(struct wts_obj)); + memset(wts, 0, sizeof(struct wts_obj)); + wts->fd = -1; + wts->flags = flags; + display_text = getenv("DISPLAY"); + + if (display_text != 0) + { + wts->display_num = get_display_num_from_display(display_text); + } + + if (wts->display_num > 0) + { + wts->fd = socket(AF_UNIX, SOCK_STREAM, 0); + /* set non blocking */ + llong = fcntl(wts->fd, F_GETFL); + llong = llong | O_NONBLOCK; + fcntl(wts->fd, F_SETFL, llong); + /* connect to session chansrv */ + memset(&s, 0, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + bytes = sizeof(s.sun_path); + snprintf(s.sun_path, bytes - 1, "/tmp/.xrdp/xrdpapi_%d", wts->display_num); + s.sun_path[bytes - 1] = 0; + bytes = sizeof(struct sockaddr_un); + + if (connect(wts->fd, (struct sockaddr *)&s, bytes) == 0) + { + LLOGLN(10, ("WTSVirtualChannelOpenEx: connected ok, name %s", pVirtualName)); + strncpy(wts->name, pVirtualName, 8); + + /* wait for connection to complete and send init */ + if (send_init(wts) == 0) + { + /* all ok */ + wts->status = 1; + } + } + } + else + { + LLOGLN(0, ("WTSVirtualChannelOpenEx: display is 0")); + } + + return wts; } /*****************************************************************************/ int -WTSVirtualChannelWrite(void* hChannelHandle, const char* Buffer, - unsigned int Length, unsigned int* pBytesWritten) +WTSVirtualChannelWrite(void *hChannelHandle, const char *Buffer, + unsigned int Length, unsigned int *pBytesWritten) { - struct wts_obj* wts; - int error; - int lerrno; + struct wts_obj *wts; + int error; + int lerrno; - wts = (struct wts_obj*)hChannelHandle; - if (wts == 0) - { - return 0; - } - if (wts->status != 1) - { - return 0; - } - if (can_send(wts->fd, 0)) - { - error = send(wts->fd, Buffer, Length, 0); - if (error == -1) + wts = (struct wts_obj *)hChannelHandle; + + if (wts == 0) { - lerrno = errno; - if ((lerrno == EWOULDBLOCK) || (lerrno == EAGAIN) || - (lerrno == EINPROGRESS)) - { - *pBytesWritten = 0; - return 1; - } - return 0; + return 0; } - else if (error == 0) + + if (wts->status != 1) { - return 0; + return 0; } - else if (error > 0) + + if (can_send(wts->fd, 0)) { - *pBytesWritten = error; - return 1; + error = send(wts->fd, Buffer, Length, 0); + + if (error == -1) + { + lerrno = errno; + + if ((lerrno == EWOULDBLOCK) || (lerrno == EAGAIN) || + (lerrno == EINPROGRESS)) + { + *pBytesWritten = 0; + return 1; + } + + return 0; + } + else if (error == 0) + { + return 0; + } + else if (error > 0) + { + *pBytesWritten = error; + return 1; + } } - } - *pBytesWritten = 0; - return 1; + + *pBytesWritten = 0; + return 1; } /*****************************************************************************/ int -WTSVirtualChannelRead(void* hChannelHandle, unsigned int TimeOut, - char* Buffer, unsigned int BufferSize, - unsigned int* pBytesRead) +WTSVirtualChannelRead(void *hChannelHandle, unsigned int TimeOut, + char *Buffer, unsigned int BufferSize, + unsigned int *pBytesRead) { - struct wts_obj* wts; - int error; - int lerrno; + struct wts_obj *wts; + int error; + int lerrno; - wts = (struct wts_obj*)hChannelHandle; - if (wts == 0) - { - return 0; - } - if (wts->status != 1) - { - return 0; - } - if (can_recv(wts->fd, TimeOut)) - { - error = recv(wts->fd, Buffer, BufferSize, 0); - if (error == -1) + wts = (struct wts_obj *)hChannelHandle; + + if (wts == 0) { - lerrno = errno; - if ((lerrno == EWOULDBLOCK) || (lerrno == EAGAIN) || - (lerrno == EINPROGRESS)) - { - *pBytesRead = 0; - return 1; - } - return 0; + return 0; } - else if (error == 0) + + if (wts->status != 1) { - return 0; + return 0; } - else if (error > 0) + + if (can_recv(wts->fd, TimeOut)) { - *pBytesRead = error; - return 1; + error = recv(wts->fd, Buffer, BufferSize, 0); + + if (error == -1) + { + lerrno = errno; + + if ((lerrno == EWOULDBLOCK) || (lerrno == EAGAIN) || + (lerrno == EINPROGRESS)) + { + *pBytesRead = 0; + return 1; + } + + return 0; + } + else if (error == 0) + { + return 0; + } + else if (error > 0) + { + *pBytesRead = error; + return 1; + } } - } - *pBytesRead = 0; - return 1; + + *pBytesRead = 0; + return 1; } /*****************************************************************************/ int -WTSVirtualChannelClose(void* hChannelHandle) +WTSVirtualChannelClose(void *hChannelHandle) { - struct wts_obj* wts; + struct wts_obj *wts; - wts = (struct wts_obj*)hChannelHandle; - if (wts == 0) - { - return 0; - } - if (wts->fd != -1) - { - close(wts->fd); - } - free(wts); - return 1; + wts = (struct wts_obj *)hChannelHandle; + + if (wts == 0) + { + return 0; + } + + if (wts->fd != -1) + { + close(wts->fd); + } + + free(wts); + return 1; } /*****************************************************************************/ int -WTSVirtualChannelQuery(void* hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass, - void** ppBuffer, unsigned int* pBytesReturned) +WTSVirtualChannelQuery(void *hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass, + void **ppBuffer, unsigned int *pBytesReturned) { - struct wts_obj* wts; + struct wts_obj *wts; - wts = (struct wts_obj*)hChannelHandle; - if (wts == 0) - { - return 0; - } - if (wts->status != 1) - { - return 0; - } - if (WtsVirtualClass == WTSVirtualFileHandle) - { - *pBytesReturned = 4; - *ppBuffer = malloc(4); - memcpy(*ppBuffer, &(wts->fd), 4); - } - return 1; + wts = (struct wts_obj *)hChannelHandle; + + if (wts == 0) + { + return 0; + } + + if (wts->status != 1) + { + return 0; + } + + if (WtsVirtualClass == WTSVirtualFileHandle) + { + *pBytesReturned = 4; + *ppBuffer = malloc(4); + memcpy(*ppBuffer, &(wts->fd), 4); + } + + return 1; } /*****************************************************************************/ void -WTSFreeMemory(void* pMemory) +WTSFreeMemory(void *pMemory) { - if (pMemory != 0) - { - free(pMemory); - } + if (pMemory != 0) + { + free(pMemory); + } } diff --git a/xrdpapi/xrdpapi.h b/xrdpapi/xrdpapi.h index 65b6db42..82f9b809 100644 --- a/xrdpapi/xrdpapi.h +++ b/xrdpapi/xrdpapi.h @@ -16,10 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /* - xrdpapi header, do not use os_calls.h, arch.h or any xrdp internal headers - this file is included in 3rd party apps -*/ + * xrdpapi header, do not use os_calls.h, arch.h or any xrdp internal headers + * this file is included in 3rd party apps + */ #if !defined(XRDPAPI_H_) #define XRDPAPI_H_ diff --git a/xup/xup.c b/xup/xup.c index 3c95c1e0..15498e64 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -1,828 +1,887 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2012 - - libxup main file - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * libxup main file + */ #include "xup.h" /******************************************************************************/ /* returns error */ int DEFAULT_CC -lib_recv(struct mod* mod, char* data, int len) +lib_recv(struct mod *mod, char *data, int len) { - int rcvd; + int rcvd; - if (mod->sck_closed) - { - return 1; - } - while (len > 0) - { - rcvd = g_tcp_recv(mod->sck, data, len, 0); - if (rcvd == -1) + if (mod->sck_closed) { - if (g_tcp_last_error_would_block(mod->sck)) - { - if (mod->server_is_term(mod)) - { - return 1; - } - g_tcp_can_recv(mod->sck, 10); - } - else - { return 1; - } } - else if (rcvd == 0) + + while (len > 0) { - mod->sck_closed = 1; - return 1; + rcvd = g_tcp_recv(mod->sck, data, len, 0); + + if (rcvd == -1) + { + if (g_tcp_last_error_would_block(mod->sck)) + { + if (mod->server_is_term(mod)) + { + return 1; + } + + g_tcp_can_recv(mod->sck, 10); + } + else + { + return 1; + } + } + else if (rcvd == 0) + { + mod->sck_closed = 1; + return 1; + } + else + { + data += rcvd; + len -= rcvd; + } } - else - { - data += rcvd; - len -= rcvd; - } - } - return 0; + + return 0; } /*****************************************************************************/ /* returns error */ int DEFAULT_CC -lib_send(struct mod* mod, char* data, int len) +lib_send(struct mod *mod, char *data, int len) { - int sent; + int sent; - if (mod->sck_closed) - { - return 1; - } - while (len > 0) - { - sent = g_tcp_send(mod->sck, data, len, 0); - if (sent == -1) + if (mod->sck_closed) { - if (g_tcp_last_error_would_block(mod->sck)) - { - if (mod->server_is_term(mod)) - { - return 1; - } - g_tcp_can_send(mod->sck, 10); - } - else - { return 1; - } } - else if (sent == 0) - { - mod->sck_closed = 1; - return 1; - } - else - { - data += sent; - len -= sent; - } - } - return 0; -} -/******************************************************************************/ -/* return error */ -int DEFAULT_CC -lib_mod_start(struct mod* mod, int w, int h, int bpp) -{ - LIB_DEBUG(mod, "in lib_mod_start"); - mod->width = w; - mod->height = h; - mod->bpp = bpp; - LIB_DEBUG(mod, "out lib_mod_start"); - return 0; -} + while (len > 0) + { + sent = g_tcp_send(mod->sck, data, len, 0); -/******************************************************************************/ -/* return error */ -int DEFAULT_CC -lib_mod_connect(struct mod* mod) -{ - int error; - int len; - int i; - int index; - int use_uds; - struct stream* s; - char con_port[256]; - - LIB_DEBUG(mod, "in lib_mod_connect"); - /* clear screen */ - mod->server_begin_update(mod); - mod->server_set_fgcolor(mod, 0); - mod->server_fill_rect(mod, 0, 0, mod->width, mod->height); - mod->server_end_update(mod); - mod->server_msg(mod, "started connecting", 0); - /* only support 8, 15, 16, and 24 bpp connections from rdp client */ - if (mod->bpp != 8 && mod->bpp != 15 && mod->bpp != 16 && mod->bpp != 24) - { - mod->server_msg(mod, - "error - only supporting 8, 15, 16, and 24 bpp rdp connections", 0); - LIB_DEBUG(mod, "out lib_mod_connect error"); - return 1; - } - if (g_strcmp(mod->ip, "") == 0) - { - mod->server_msg(mod, "error - no ip set", 0); - LIB_DEBUG(mod, "out lib_mod_connect error"); - return 1; - } - make_stream(s); - g_sprintf(con_port, "%s", mod->port); - use_uds = 0; - if (con_port[0] == '/') - { - use_uds = 1; - } - mod->sck_closed = 0; - i = 0; - while (1) - { - if (use_uds) - { - mod->sck = g_tcp_local_socket(); - } - else - { - mod->sck = g_tcp_socket(); - g_tcp_set_non_blocking(mod->sck); - g_tcp_set_no_delay(mod->sck); - } - mod->server_msg(mod, "connecting...", 0); - if (use_uds) - { - error = g_tcp_local_connect(mod->sck, con_port); - } - else - { - error = g_tcp_connect(mod->sck, mod->ip, con_port); - } - if (error == -1) - { - if (g_tcp_last_error_would_block(mod->sck)) - { - error = 0; - index = 0; - while (!g_tcp_can_send(mod->sck, 100)) + if (sent == -1) { - index++; - if ((index >= 30) || mod->server_is_term(mod)) - { - mod->server_msg(mod, "connect timeout", 0); - error = 1; - break; - } + if (g_tcp_last_error_would_block(mod->sck)) + { + if (mod->server_is_term(mod)) + { + return 1; + } + + g_tcp_can_send(mod->sck, 10); + } + else + { + return 1; + } + } + else if (sent == 0) + { + mod->sck_closed = 1; + return 1; + } + else + { + data += sent; + len -= sent; } - } - else - { - mod->server_msg(mod, "connect error", 0); - } } + + return 0; +} + +/******************************************************************************/ +/* return error */ +int DEFAULT_CC +lib_mod_start(struct mod *mod, int w, int h, int bpp) +{ + LIB_DEBUG(mod, "in lib_mod_start"); + mod->width = w; + mod->height = h; + mod->bpp = bpp; + LIB_DEBUG(mod, "out lib_mod_start"); + return 0; +} + +/******************************************************************************/ +/* return error */ +int DEFAULT_CC +lib_mod_connect(struct mod *mod) +{ + int error; + int len; + int i; + int index; + int use_uds; + struct stream *s; + char con_port[256]; + + LIB_DEBUG(mod, "in lib_mod_connect"); + /* clear screen */ + mod->server_begin_update(mod); + mod->server_set_fgcolor(mod, 0); + mod->server_fill_rect(mod, 0, 0, mod->width, mod->height); + mod->server_end_update(mod); + mod->server_msg(mod, "started connecting", 0); + + /* only support 8, 15, 16, and 24 bpp connections from rdp client */ + if (mod->bpp != 8 && mod->bpp != 15 && mod->bpp != 16 && mod->bpp != 24) + { + mod->server_msg(mod, + "error - only supporting 8, 15, 16, and 24 bpp rdp connections", 0); + LIB_DEBUG(mod, "out lib_mod_connect error"); + return 1; + } + + if (g_strcmp(mod->ip, "") == 0) + { + mod->server_msg(mod, "error - no ip set", 0); + LIB_DEBUG(mod, "out lib_mod_connect error"); + return 1; + } + + make_stream(s); + g_sprintf(con_port, "%s", mod->port); + use_uds = 0; + + if (con_port[0] == '/') + { + use_uds = 1; + } + + mod->sck_closed = 0; + i = 0; + + while (1) + { + if (use_uds) + { + mod->sck = g_tcp_local_socket(); + } + else + { + mod->sck = g_tcp_socket(); + g_tcp_set_non_blocking(mod->sck); + g_tcp_set_no_delay(mod->sck); + } + + mod->server_msg(mod, "connecting...", 0); + + if (use_uds) + { + error = g_tcp_local_connect(mod->sck, con_port); + } + else + { + error = g_tcp_connect(mod->sck, mod->ip, con_port); + } + + if (error == -1) + { + if (g_tcp_last_error_would_block(mod->sck)) + { + error = 0; + index = 0; + + while (!g_tcp_can_send(mod->sck, 100)) + { + index++; + + if ((index >= 30) || mod->server_is_term(mod)) + { + mod->server_msg(mod, "connect timeout", 0); + error = 1; + break; + } + } + } + else + { + mod->server_msg(mod, "connect error", 0); + } + } + + if (error == 0) + { + break; + } + + g_tcp_close(mod->sck); + mod->sck = 0; + i++; + + if (i >= 4) + { + mod->server_msg(mod, "connection problem, giving up", 0); + break; + } + + g_sleep(250); + } + if (error == 0) { - break; + /* send version message */ + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 103); + out_uint32_le(s, 301); + out_uint32_le(s, 0); + out_uint32_le(s, 0); + out_uint32_le(s, 0); + out_uint32_le(s, 1); + s_mark_end(s); + len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + lib_send(mod, s->data, len); } - g_tcp_close(mod->sck); - mod->sck = 0; - i++; - if (i >= 4) + + if (error == 0) { - mod->server_msg(mod, "connection problem, giving up", 0); - break; + /* send screen size message */ + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 103); + out_uint32_le(s, 300); + out_uint32_le(s, mod->width); + out_uint32_le(s, mod->height); + out_uint32_le(s, mod->bpp); + out_uint32_le(s, 0); + s_mark_end(s); + len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + lib_send(mod, s->data, len); } - g_sleep(250); - } - if (error == 0) - { - /* send version message */ - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 103); - out_uint32_le(s, 301); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - out_uint32_le(s, 1); - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - lib_send(mod, s->data, len); - } - if (error == 0) - { - /* send screen size message */ - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 103); - out_uint32_le(s, 300); - out_uint32_le(s, mod->width); - out_uint32_le(s, mod->height); - out_uint32_le(s, mod->bpp); - out_uint32_le(s, 0); - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - lib_send(mod, s->data, len); - } - if (error == 0) - { - /* send invalidate message */ - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 103); - out_uint32_le(s, 200); - /* x and y */ - i = 0; - out_uint32_le(s, i); - /* width and height */ - i = ((mod->width & 0xffff) << 16) | mod->height; - out_uint32_le(s, i); - out_uint32_le(s, 0); - out_uint32_le(s, 0); - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - lib_send(mod, s->data, len); - } - free_stream(s); - if (error != 0) - { - mod->server_msg(mod, "some problem", 0); - LIB_DEBUG(mod, "out lib_mod_connect error"); - return 1; - } - else - { - mod->server_msg(mod, "connected ok", 0); - mod->sck_obj = g_create_wait_obj_from_socket(mod->sck, 0); - } - LIB_DEBUG(mod, "out lib_mod_connect"); - return 0; + + if (error == 0) + { + /* send invalidate message */ + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 103); + out_uint32_le(s, 200); + /* x and y */ + i = 0; + out_uint32_le(s, i); + /* width and height */ + i = ((mod->width & 0xffff) << 16) | mod->height; + out_uint32_le(s, i); + out_uint32_le(s, 0); + out_uint32_le(s, 0); + s_mark_end(s); + len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + lib_send(mod, s->data, len); + } + + free_stream(s); + + if (error != 0) + { + mod->server_msg(mod, "some problem", 0); + LIB_DEBUG(mod, "out lib_mod_connect error"); + return 1; + } + else + { + mod->server_msg(mod, "connected ok", 0); + mod->sck_obj = g_create_wait_obj_from_socket(mod->sck, 0); + } + + LIB_DEBUG(mod, "out lib_mod_connect"); + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_event(struct mod* mod, int msg, tbus param1, tbus param2, +lib_mod_event(struct mod *mod, int msg, tbus param1, tbus param2, tbus param3, tbus param4) { - struct stream* s; - int len; - int key; - int rv; + struct stream *s; + int len; + int key; + int rv; - LIB_DEBUG(mod, "in lib_mod_event"); - make_stream(s); - if ((msg >= 15) && (msg <= 16)) /* key events */ - { - key = param2; - if (key > 0) + LIB_DEBUG(mod, "in lib_mod_event"); + make_stream(s); + + if ((msg >= 15) && (msg <= 16)) /* key events */ { - if (key == 65027) /* altgr */ - { - if (mod->shift_state) + key = param2; + + if (key > 0) { - g_writeln("special"); - /* fix for mstsc sending left control down with altgr */ - /* control down / up - msg param1 param2 param3 param4 - 15 0 65507 29 0 - 16 0 65507 29 49152 */ - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 103); - out_uint32_le(s, 16); /* key up */ - out_uint32_le(s, 0); - out_uint32_le(s, 65507); /* left control */ - out_uint32_le(s, 29); /* RDP scan code */ - out_uint32_le(s, 0xc000); /* flags */ - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - lib_send(mod, s->data, len); + if (key == 65027) /* altgr */ + { + if (mod->shift_state) + { + g_writeln("special"); + /* fix for mstsc sending left control down with altgr */ + /* control down / up + msg param1 param2 param3 param4 + 15 0 65507 29 0 + 16 0 65507 29 49152 */ + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 103); + out_uint32_le(s, 16); /* key up */ + out_uint32_le(s, 0); + out_uint32_le(s, 65507); /* left control */ + out_uint32_le(s, 29); /* RDP scan code */ + out_uint32_le(s, 0xc000); /* flags */ + s_mark_end(s); + len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + lib_send(mod, s->data, len); + } + } + + if (key == 65507) /* left control */ + { + mod->shift_state = msg == 15; + } } - } - if (key == 65507) /* left control */ - { - mod->shift_state = msg == 15; - } } - } - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 103); - out_uint32_le(s, msg); - out_uint32_le(s, param1); - out_uint32_le(s, param2); - out_uint32_le(s, param3); - out_uint32_le(s, param4); - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - rv = lib_send(mod, s->data, len); - free_stream(s); - LIB_DEBUG(mod, "out lib_mod_event"); - return rv; + + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 103); + out_uint32_le(s, msg); + out_uint32_le(s, param1); + out_uint32_le(s, param2); + out_uint32_le(s, param3); + out_uint32_le(s, param4); + s_mark_end(s); + len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + rv = lib_send(mod, s->data, len); + free_stream(s); + LIB_DEBUG(mod, "out lib_mod_event"); + return rv; } /******************************************************************************/ /* return error */ static int APP_CC -process_server_window_new_update(struct mod* mod, struct stream* s) +process_server_window_new_update(struct mod *mod, struct stream *s) { - int flags; - int window_id; - int title_bytes; - int index; - int bytes; - int rv; - struct rail_window_state_order rwso; + int flags; + int window_id; + int title_bytes; + int index; + int bytes; + int rv; + struct rail_window_state_order rwso; - g_memset(&rwso, 0, sizeof(rwso)); - in_uint32_le(s, window_id); - in_uint32_le(s, rwso.owner_window_id); - in_uint32_le(s, rwso.style); - in_uint32_le(s, rwso.extended_style); - in_uint32_le(s, rwso.show_state); - in_uint16_le(s, title_bytes); - if (title_bytes > 0) - { - rwso.title_info = g_malloc(title_bytes + 1, 0); - in_uint8a(s, rwso.title_info, title_bytes); - rwso.title_info[title_bytes] = 0; - } - in_uint32_le(s, rwso.client_offset_x); - in_uint32_le(s, rwso.client_offset_y); - in_uint32_le(s, rwso.client_area_width); - in_uint32_le(s, rwso.client_area_height); - in_uint32_le(s, rwso.rp_content); - in_uint32_le(s, rwso.root_parent_handle); - in_uint32_le(s, rwso.window_offset_x); - in_uint32_le(s, rwso.window_offset_y); - in_uint32_le(s, rwso.window_client_delta_x); - in_uint32_le(s, rwso.window_client_delta_y); - in_uint32_le(s, rwso.window_width); - in_uint32_le(s, rwso.window_height); - in_uint16_le(s, rwso.num_window_rects); - if (rwso.num_window_rects > 0) - { - bytes = sizeof(struct rail_window_rect) * rwso.num_window_rects; - rwso.window_rects = (struct rail_window_rect*)g_malloc(bytes, 0); - for (index = 0; index < rwso.num_window_rects; index++) + g_memset(&rwso, 0, sizeof(rwso)); + in_uint32_le(s, window_id); + in_uint32_le(s, rwso.owner_window_id); + in_uint32_le(s, rwso.style); + in_uint32_le(s, rwso.extended_style); + in_uint32_le(s, rwso.show_state); + in_uint16_le(s, title_bytes); + + if (title_bytes > 0) { - in_uint16_le(s, rwso.window_rects[index].left); - in_uint16_le(s, rwso.window_rects[index].top); - in_uint16_le(s, rwso.window_rects[index].right); - in_uint16_le(s, rwso.window_rects[index].bottom); + rwso.title_info = g_malloc(title_bytes + 1, 0); + in_uint8a(s, rwso.title_info, title_bytes); + rwso.title_info[title_bytes] = 0; } - } - in_uint32_le(s, rwso.visible_offset_x); - in_uint32_le(s, rwso.visible_offset_y); - in_uint16_le(s, rwso.num_visibility_rects); - if (rwso.num_visibility_rects > 0) - { - bytes = sizeof(struct rail_window_rect) * rwso.num_visibility_rects; - rwso.visibility_rects = (struct rail_window_rect*)g_malloc(bytes, 0); - for (index = 0; index < rwso.num_visibility_rects; index++) + + in_uint32_le(s, rwso.client_offset_x); + in_uint32_le(s, rwso.client_offset_y); + in_uint32_le(s, rwso.client_area_width); + in_uint32_le(s, rwso.client_area_height); + in_uint32_le(s, rwso.rp_content); + in_uint32_le(s, rwso.root_parent_handle); + in_uint32_le(s, rwso.window_offset_x); + in_uint32_le(s, rwso.window_offset_y); + in_uint32_le(s, rwso.window_client_delta_x); + in_uint32_le(s, rwso.window_client_delta_y); + in_uint32_le(s, rwso.window_width); + in_uint32_le(s, rwso.window_height); + in_uint16_le(s, rwso.num_window_rects); + + if (rwso.num_window_rects > 0) { - in_uint16_le(s, rwso.visibility_rects[index].left); - in_uint16_le(s, rwso.visibility_rects[index].top); - in_uint16_le(s, rwso.visibility_rects[index].right); - in_uint16_le(s, rwso.visibility_rects[index].bottom); + bytes = sizeof(struct rail_window_rect) * rwso.num_window_rects; + rwso.window_rects = (struct rail_window_rect *)g_malloc(bytes, 0); + + for (index = 0; index < rwso.num_window_rects; index++) + { + in_uint16_le(s, rwso.window_rects[index].left); + in_uint16_le(s, rwso.window_rects[index].top); + in_uint16_le(s, rwso.window_rects[index].right); + in_uint16_le(s, rwso.window_rects[index].bottom); + } } - } - in_uint32_le(s, flags); - mod->server_window_new_update(mod, window_id, &rwso, flags); - rv = 0; - g_free(rwso.title_info); - g_free(rwso.window_rects); - g_free(rwso.visibility_rects); - return rv; + + in_uint32_le(s, rwso.visible_offset_x); + in_uint32_le(s, rwso.visible_offset_y); + in_uint16_le(s, rwso.num_visibility_rects); + + if (rwso.num_visibility_rects > 0) + { + bytes = sizeof(struct rail_window_rect) * rwso.num_visibility_rects; + rwso.visibility_rects = (struct rail_window_rect *)g_malloc(bytes, 0); + + for (index = 0; index < rwso.num_visibility_rects; index++) + { + in_uint16_le(s, rwso.visibility_rects[index].left); + in_uint16_le(s, rwso.visibility_rects[index].top); + in_uint16_le(s, rwso.visibility_rects[index].right); + in_uint16_le(s, rwso.visibility_rects[index].bottom); + } + } + + in_uint32_le(s, flags); + mod->server_window_new_update(mod, window_id, &rwso, flags); + rv = 0; + g_free(rwso.title_info); + g_free(rwso.window_rects); + g_free(rwso.visibility_rects); + return rv; } /******************************************************************************/ /* return error */ static int APP_CC -process_server_window_delete(struct mod* mod, struct stream* s) +process_server_window_delete(struct mod *mod, struct stream *s) { - int window_id; - int rv; + int window_id; + int rv; - in_uint32_le(s, window_id); - mod->server_window_delete(mod, window_id); - rv = 0; - return rv; + in_uint32_le(s, window_id); + mod->server_window_delete(mod, window_id); + rv = 0; + return rv; } /******************************************************************************/ /* return error */ static int -lib_mod_process_orders(struct mod* mod, int type, struct stream* s) +lib_mod_process_orders(struct mod *mod, int type, struct stream *s) { - int rv; - int x; - int y; - int cx; - int cy; - int srcx; - int srcy; - int len_bmpdata; - int style; - int x1; - int y1; - int x2; - int y2; - int rdpid; - int hints; - int mask; - int width; - int height; - int fgcolor; - int opcode; - char* bmpdata; - char cur_data[32 * (32 * 3)]; - char cur_mask[32 * (32 / 8)]; + int rv; + int x; + int y; + int cx; + int cy; + int srcx; + int srcy; + int len_bmpdata; + int style; + int x1; + int y1; + int x2; + int y2; + int rdpid; + int hints; + int mask; + int width; + int height; + int fgcolor; + int opcode; + char *bmpdata; + char cur_data[32 * (32 * 3)]; + char cur_mask[32 * (32 / 8)]; - rv = 0; - switch (type) - { - case 1: /* server_begin_update */ - rv = mod->server_begin_update(mod); - break; - case 2: /* server_end_update */ - rv = mod->server_end_update(mod); - break; - case 3: /* server_fill_rect */ - in_sint16_le(s, x); - in_sint16_le(s, y); - in_uint16_le(s, cx); - in_uint16_le(s, cy); - rv = mod->server_fill_rect(mod, x, y, cx, cy); - break; - case 4: /* server_screen_blt */ - in_sint16_le(s, x); - in_sint16_le(s, y); - in_uint16_le(s, cx); - in_uint16_le(s, cy); - in_sint16_le(s, srcx); - in_sint16_le(s, srcy); - rv = mod->server_screen_blt(mod, x, y, cx, cy, srcx, srcy); - break; - case 5: /* server_paint_rect */ - in_sint16_le(s, x); - in_sint16_le(s, y); - in_uint16_le(s, cx); - in_uint16_le(s, cy); - in_uint32_le(s, len_bmpdata); - in_uint8p(s, bmpdata, len_bmpdata); - in_uint16_le(s, width); - in_uint16_le(s, height); - in_sint16_le(s, srcx); - in_sint16_le(s, srcy); - rv = mod->server_paint_rect(mod, x, y, cx, cy, - bmpdata, width, height, - srcx, srcy); - break; - case 10: /* server_set_clip */ - in_sint16_le(s, x); - in_sint16_le(s, y); - in_uint16_le(s, cx); - in_uint16_le(s, cy); - rv = mod->server_set_clip(mod, x, y, cx, cy); - break; - case 11: /* server_reset_clip */ - rv = mod->server_reset_clip(mod); - break; - case 12: /* server_set_fgcolor */ - in_uint32_le(s, fgcolor); - rv = mod->server_set_fgcolor(mod, fgcolor); - break; - case 14: - in_uint16_le(s, opcode); - rv = mod->server_set_opcode(mod, opcode); - break; - case 17: - in_uint16_le(s, style); - in_uint16_le(s, width); - rv = mod->server_set_pen(mod, style, width); - break; - case 18: - in_sint16_le(s, x1); - in_sint16_le(s, y1); - in_sint16_le(s, x2); - in_sint16_le(s, y2); - rv = mod->server_draw_line(mod, x1, y1, x2, y2); - break; - case 19: - in_sint16_le(s, x); - in_sint16_le(s, y); - in_uint8a(s, cur_data, 32 * (32 * 3)); - in_uint8a(s, cur_mask, 32 * (32 / 8)); - rv = mod->server_set_cursor(mod, x, y, cur_data, cur_mask); - break; - case 20: - in_uint32_le(s, rdpid); - in_uint16_le(s, width); - in_uint16_le(s, height); - rv = mod->server_create_os_surface(mod, rdpid, width, height); - break; - case 21: - in_uint32_le(s, rdpid); - rv = mod->server_switch_os_surface(mod, rdpid); - break; - case 22: - in_uint32_le(s, rdpid); - rv = mod->server_delete_os_surface(mod, rdpid); - break; - case 23: /* server_paint_rect_os */ - in_sint16_le(s, x); - in_sint16_le(s, y); - in_uint16_le(s, cx); - in_uint16_le(s, cy); - in_uint32_le(s, rdpid); - in_sint16_le(s, srcx); - in_sint16_le(s, srcy); - rv = mod->server_paint_rect_os(mod, x, y, cx, cy, - rdpid, srcx, srcy); - break; - case 24: /* server_set_hints */ - in_uint32_le(s, hints); - in_uint32_le(s, mask); - rv = mod->server_set_hints(mod, hints, mask); - break; - case 25: /* server_window_new_update */ - rv = process_server_window_new_update(mod, s); - break; - case 26: /* server_window_delete */ - rv = process_server_window_delete(mod, s); - break; - default: - g_writeln("lib_mod_process_orders: unknown order type %d", type); - rv = 0; - break; - } - return rv; + rv = 0; + + switch (type) + { + case 1: /* server_begin_update */ + rv = mod->server_begin_update(mod); + break; + case 2: /* server_end_update */ + rv = mod->server_end_update(mod); + break; + case 3: /* server_fill_rect */ + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + rv = mod->server_fill_rect(mod, x, y, cx, cy); + break; + case 4: /* server_screen_blt */ + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + in_sint16_le(s, srcx); + in_sint16_le(s, srcy); + rv = mod->server_screen_blt(mod, x, y, cx, cy, srcx, srcy); + break; + case 5: /* server_paint_rect */ + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + in_uint32_le(s, len_bmpdata); + in_uint8p(s, bmpdata, len_bmpdata); + in_uint16_le(s, width); + in_uint16_le(s, height); + in_sint16_le(s, srcx); + in_sint16_le(s, srcy); + rv = mod->server_paint_rect(mod, x, y, cx, cy, + bmpdata, width, height, + srcx, srcy); + break; + case 10: /* server_set_clip */ + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + rv = mod->server_set_clip(mod, x, y, cx, cy); + break; + case 11: /* server_reset_clip */ + rv = mod->server_reset_clip(mod); + break; + case 12: /* server_set_fgcolor */ + in_uint32_le(s, fgcolor); + rv = mod->server_set_fgcolor(mod, fgcolor); + break; + case 14: + in_uint16_le(s, opcode); + rv = mod->server_set_opcode(mod, opcode); + break; + case 17: + in_uint16_le(s, style); + in_uint16_le(s, width); + rv = mod->server_set_pen(mod, style, width); + break; + case 18: + in_sint16_le(s, x1); + in_sint16_le(s, y1); + in_sint16_le(s, x2); + in_sint16_le(s, y2); + rv = mod->server_draw_line(mod, x1, y1, x2, y2); + break; + case 19: + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint8a(s, cur_data, 32 * (32 * 3)); + in_uint8a(s, cur_mask, 32 * (32 / 8)); + rv = mod->server_set_cursor(mod, x, y, cur_data, cur_mask); + break; + case 20: + in_uint32_le(s, rdpid); + in_uint16_le(s, width); + in_uint16_le(s, height); + rv = mod->server_create_os_surface(mod, rdpid, width, height); + break; + case 21: + in_uint32_le(s, rdpid); + rv = mod->server_switch_os_surface(mod, rdpid); + break; + case 22: + in_uint32_le(s, rdpid); + rv = mod->server_delete_os_surface(mod, rdpid); + break; + case 23: /* server_paint_rect_os */ + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + in_uint32_le(s, rdpid); + in_sint16_le(s, srcx); + in_sint16_le(s, srcy); + rv = mod->server_paint_rect_os(mod, x, y, cx, cy, + rdpid, srcx, srcy); + break; + case 24: /* server_set_hints */ + in_uint32_le(s, hints); + in_uint32_le(s, mask); + rv = mod->server_set_hints(mod, hints, mask); + break; + case 25: /* server_window_new_update */ + rv = process_server_window_new_update(mod, s); + break; + case 26: /* server_window_delete */ + rv = process_server_window_delete(mod, s); + break; + default: + g_writeln("lib_mod_process_orders: unknown order type %d", type); + rv = 0; + break; + } + + return rv; } /******************************************************************************/ /* return error */ static int APP_CC -lib_send_client_info(struct mod* mod) +lib_send_client_info(struct mod *mod) { - struct stream* s; - int len; + struct stream *s; + int len; - make_stream(s); - init_stream(s, 8192); - s_push_layer(s, iso_hdr, 4); - out_uint16_le(s, 104); - g_memcpy(s->p, &(mod->client_info), sizeof(mod->client_info)); - s->p += sizeof(mod->client_info); - s_mark_end(s); - len = (int)(s->end - s->data); - s_pop_layer(s, iso_hdr); - out_uint32_le(s, len); - lib_send(mod, s->data, len); - free_stream(s); - return 0; + make_stream(s); + init_stream(s, 8192); + s_push_layer(s, iso_hdr, 4); + out_uint16_le(s, 104); + g_memcpy(s->p, &(mod->client_info), sizeof(mod->client_info)); + s->p += sizeof(mod->client_info); + s_mark_end(s); + len = (int)(s->end - s->data); + s_pop_layer(s, iso_hdr); + out_uint32_le(s, len); + lib_send(mod, s->data, len); + free_stream(s); + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_signal(struct mod* mod) +lib_mod_signal(struct mod *mod) { - struct stream* s; - int num_orders; - int index; - int rv; - int len; - int type; - char* phold; + struct stream *s; + int num_orders; + int index; + int rv; + int len; + int type; + char *phold; - LIB_DEBUG(mod, "in lib_mod_signal"); - make_stream(s); - init_stream(s, 8192); - rv = lib_recv(mod, s->data, 8); - if (rv == 0) - { - in_uint16_le(s, type); - in_uint16_le(s, num_orders); - in_uint32_le(s, len); - if (type == 1) /* original order list */ + LIB_DEBUG(mod, "in lib_mod_signal"); + make_stream(s); + init_stream(s, 8192); + rv = lib_recv(mod, s->data, 8); + + if (rv == 0) { - init_stream(s, len); - rv = lib_recv(mod, s->data, len); - if (rv == 0) - { - for (index = 0; index < num_orders; index++) + in_uint16_le(s, type); + in_uint16_le(s, num_orders); + in_uint32_le(s, len); + + if (type == 1) /* original order list */ { - in_uint16_le(s, type); - rv = lib_mod_process_orders(mod, type, s); - if (rv != 0) - { - break; - } + init_stream(s, len); + rv = lib_recv(mod, s->data, len); + + if (rv == 0) + { + for (index = 0; index < num_orders; index++) + { + in_uint16_le(s, type); + rv = lib_mod_process_orders(mod, type, s); + + if (rv != 0) + { + break; + } + } + } } - } - } - else if (type == 2) /* caps */ - { - g_writeln("lib_mod_signal: type 2 len %d", len); - init_stream(s, len); - rv = lib_recv(mod, s->data, len); - if (rv == 0) - { - for (index = 0; index < num_orders; index++) + else if (type == 2) /* caps */ { - phold = s->p; - in_uint16_le(s, type); - in_uint16_le(s, len); - switch (type) - { - default: - g_writeln("lib_mod_signal: unknown cap type %d len %d", - type, len); - break; - } - s->p = phold + len; + g_writeln("lib_mod_signal: type 2 len %d", len); + init_stream(s, len); + rv = lib_recv(mod, s->data, len); + + if (rv == 0) + { + for (index = 0; index < num_orders; index++) + { + phold = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + + switch (type) + { + default: + g_writeln("lib_mod_signal: unknown cap type %d len %d", + type, len); + break; + } + + s->p = phold + len; + } + + lib_send_client_info(mod); + } } - lib_send_client_info(mod); - } - } - else if (type == 3) /* order list with len after type */ - { - init_stream(s, len); - rv = lib_recv(mod, s->data, len); - if (rv == 0) - { - for (index = 0; index < num_orders; index++) + else if (type == 3) /* order list with len after type */ { - phold = s->p; - in_uint16_le(s, type); - in_uint16_le(s, len); - rv = lib_mod_process_orders(mod, type, s); - if (rv != 0) - { - break; - } - s->p = phold + len; + init_stream(s, len); + rv = lib_recv(mod, s->data, len); + + if (rv == 0) + { + for (index = 0; index < num_orders; index++) + { + phold = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + rv = lib_mod_process_orders(mod, type, s); + + if (rv != 0) + { + break; + } + + s->p = phold + len; + } + } + } + else + { + g_writeln("unknown type %d", type); } - } } - else + + free_stream(s); + LIB_DEBUG(mod, "out lib_mod_signal"); + return rv; +} + +/******************************************************************************/ +/* return error */ +int DEFAULT_CC +lib_mod_end(struct mod *mod) +{ + return 0; +} + +/******************************************************************************/ +/* return error */ +int DEFAULT_CC +lib_mod_set_param(struct mod *mod, char *name, char *value) +{ + if (g_strcasecmp(name, "username") == 0) { - g_writeln("unknown type %d", type); + g_strncpy(mod->username, value, 255); } - } - free_stream(s); - LIB_DEBUG(mod, "out lib_mod_signal"); - return rv; -} - -/******************************************************************************/ -/* return error */ -int DEFAULT_CC -lib_mod_end(struct mod* mod) -{ - return 0; -} - -/******************************************************************************/ -/* return error */ -int DEFAULT_CC -lib_mod_set_param(struct mod* mod, char* name, char* value) -{ - if (g_strcasecmp(name, "username") == 0) - { - g_strncpy(mod->username, value, 255); - } - else if (g_strcasecmp(name, "password") == 0) - { - g_strncpy(mod->password, value, 255); - } - else if (g_strcasecmp(name, "ip") == 0) - { - g_strncpy(mod->ip, value, 255); - } - else if (g_strcasecmp(name, "port") == 0) - { - g_strncpy(mod->port, value, 255); - } - else if (g_strcasecmp(name, "client_info") == 0) - { - g_memcpy(&(mod->client_info), value, sizeof(mod->client_info)); - } - return 0; -} - -/******************************************************************************/ -/* return error */ -int DEFAULT_CC -lib_mod_get_wait_objs(struct mod* mod, tbus* read_objs, int* rcount, - tbus* write_objs, int* wcount, int* timeout) -{ - int i; - - i = *rcount; - if (mod != 0) - { - if (mod->sck_obj != 0) + else if (g_strcasecmp(name, "password") == 0) { - read_objs[i++] = mod->sck_obj; + g_strncpy(mod->password, value, 255); } - } - *rcount = i; - return 0; + else if (g_strcasecmp(name, "ip") == 0) + { + g_strncpy(mod->ip, value, 255); + } + else if (g_strcasecmp(name, "port") == 0) + { + g_strncpy(mod->port, value, 255); + } + else if (g_strcasecmp(name, "client_info") == 0) + { + g_memcpy(&(mod->client_info), value, sizeof(mod->client_info)); + } + + return 0; } /******************************************************************************/ /* return error */ int DEFAULT_CC -lib_mod_check_wait_objs(struct mod* mod) +lib_mod_get_wait_objs(struct mod *mod, tbus *read_objs, int *rcount, + tbus *write_objs, int *wcount, int *timeout) { - int rv; + int i; - rv = 0; - if (mod != 0) - { - if (mod->sck_obj != 0) + i = *rcount; + + if (mod != 0) { - if (g_is_wait_obj_set(mod->sck_obj)) - { - rv = lib_mod_signal(mod); - } + if (mod->sck_obj != 0) + { + read_objs[i++] = mod->sck_obj; + } } - } - return rv; + + *rcount = i; + return 0; } /******************************************************************************/ -struct mod* EXPORT_CC +/* return error */ +int DEFAULT_CC +lib_mod_check_wait_objs(struct mod *mod) +{ + int rv; + + rv = 0; + + if (mod != 0) + { + if (mod->sck_obj != 0) + { + if (g_is_wait_obj_set(mod->sck_obj)) + { + rv = lib_mod_signal(mod); + } + } + } + + return rv; +} + +/******************************************************************************/ +struct mod *EXPORT_CC mod_init(void) { - struct mod* mod; + struct mod *mod; - mod = (struct mod*)g_malloc(sizeof(struct mod), 1); - mod->size = sizeof(struct mod); - mod->version = CURRENT_MOD_VER; - mod->handle = (tbus)mod; - mod->mod_connect = lib_mod_connect; - mod->mod_start = lib_mod_start; - mod->mod_event = lib_mod_event; - mod->mod_signal = lib_mod_signal; - mod->mod_end = lib_mod_end; - mod->mod_set_param = lib_mod_set_param; - mod->mod_get_wait_objs = lib_mod_get_wait_objs; - mod->mod_check_wait_objs = lib_mod_check_wait_objs; - return mod; + mod = (struct mod *)g_malloc(sizeof(struct mod), 1); + mod->size = sizeof(struct mod); + mod->version = CURRENT_MOD_VER; + mod->handle = (tbus)mod; + mod->mod_connect = lib_mod_connect; + mod->mod_start = lib_mod_start; + mod->mod_event = lib_mod_event; + mod->mod_signal = lib_mod_signal; + mod->mod_end = lib_mod_end; + mod->mod_set_param = lib_mod_set_param; + mod->mod_get_wait_objs = lib_mod_get_wait_objs; + mod->mod_check_wait_objs = lib_mod_check_wait_objs; + return mod; } /******************************************************************************/ int EXPORT_CC -mod_exit(struct mod* mod) +mod_exit(struct mod *mod) { - if (mod == 0) - { + if (mod == 0) + { + return 0; + } + + g_delete_wait_obj_from_socket(mod->sck_obj); + g_tcp_close(mod->sck); + g_free(mod); return 0; - } - g_delete_wait_obj_from_socket(mod->sck_obj); - g_tcp_close(mod->sck); - g_free(mod); - return 0; } diff --git a/xup/xup.h b/xup/xup.h index 110d3af4..ae98c5ff 100644 --- a/xup/xup.h +++ b/xup/xup.h @@ -1,24 +1,22 @@ -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2005-2012 - - libxup main header file - -*/ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * libxup main header file + */ /* include other h files */ #include "arch.h"