Merge libguac-client-ssh.
This commit is contained in:
commit
d9cfd35647
36
protocols/ssh/.gitignore
vendored
Normal file
36
protocols/ssh/.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
# Object code
|
||||
*.o
|
||||
*.so
|
||||
*.lo
|
||||
*.la
|
||||
|
||||
# Backup files
|
||||
*~
|
||||
|
||||
# Release files
|
||||
*.tar.gz
|
||||
|
||||
# Files currently being edited by vim or vi
|
||||
*.swp
|
||||
|
||||
# automake/autoconf
|
||||
.deps/
|
||||
.libs/
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
m4/*
|
||||
!README
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
|
1
protocols/ssh/AUTHORS
Normal file
1
protocols/ssh/AUTHORS
Normal file
@ -0,0 +1 @@
|
||||
Michael Jumper <zhangmaike@users.sourceforge.net>
|
1
protocols/ssh/ChangeLog
Normal file
1
protocols/ssh/ChangeLog
Normal file
@ -0,0 +1 @@
|
||||
|
470
protocols/ssh/LICENSE
Normal file
470
protocols/ssh/LICENSE
Normal file
@ -0,0 +1,470 @@
|
||||
MOZILLA PUBLIC LICENSE
|
||||
Version 1.1
|
||||
|
||||
---------------
|
||||
|
||||
1. Definitions.
|
||||
|
||||
1.0.1. "Commercial Use" means distribution or otherwise making the
|
||||
Covered Code available to a third party.
|
||||
|
||||
1.1. "Contributor" means each entity that creates or contributes to
|
||||
the creation of Modifications.
|
||||
|
||||
1.2. "Contributor Version" means the combination of the Original
|
||||
Code, prior Modifications used by a Contributor, and the Modifications
|
||||
made by that particular Contributor.
|
||||
|
||||
1.3. "Covered Code" means the Original Code or Modifications or the
|
||||
combination of the Original Code and Modifications, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.4. "Electronic Distribution Mechanism" means a mechanism generally
|
||||
accepted in the software development community for the electronic
|
||||
transfer of data.
|
||||
|
||||
1.5. "Executable" means Covered Code in any form other than Source
|
||||
Code.
|
||||
|
||||
1.6. "Initial Developer" means the individual or entity identified
|
||||
as the Initial Developer in the Source Code notice required by Exhibit
|
||||
A.
|
||||
|
||||
1.7. "Larger Work" means a work which combines Covered Code or
|
||||
portions thereof with code not governed by the terms of this License.
|
||||
|
||||
1.8. "License" means this document.
|
||||
|
||||
1.8.1. "Licensable" means having the right to grant, to the maximum
|
||||
extent possible, whether at the time of the initial grant or
|
||||
subsequently acquired, any and all of the rights conveyed herein.
|
||||
|
||||
1.9. "Modifications" means any addition to or deletion from the
|
||||
substance or structure of either the Original Code or any previous
|
||||
Modifications. When Covered Code is released as a series of files, a
|
||||
Modification is:
|
||||
A. Any addition to or deletion from the contents of a file
|
||||
containing Original Code or previous Modifications.
|
||||
|
||||
B. Any new file that contains any part of the Original Code or
|
||||
previous Modifications.
|
||||
|
||||
1.10. "Original Code" means Source Code of computer software code
|
||||
which is described in the Source Code notice required by Exhibit A as
|
||||
Original Code, and which, at the time of its release under this
|
||||
License is not already Covered Code governed by this License.
|
||||
|
||||
1.10.1. "Patent Claims" means any patent claim(s), now owned or
|
||||
hereafter acquired, including without limitation, method, process,
|
||||
and apparatus claims, in any patent Licensable by grantor.
|
||||
|
||||
1.11. "Source Code" means the preferred form of the Covered Code for
|
||||
making modifications to it, including all modules it contains, plus
|
||||
any associated interface definition files, scripts used to control
|
||||
compilation and installation of an Executable, or source code
|
||||
differential comparisons against either the Original Code or another
|
||||
well known, available Covered Code of the Contributor's choice. The
|
||||
Source Code can be in a compressed or archival form, provided the
|
||||
appropriate decompression or de-archiving software is widely available
|
||||
for no charge.
|
||||
|
||||
1.12. "You" (or "Your") means an individual or a legal entity
|
||||
exercising rights under, and complying with all of the terms of, this
|
||||
License or a future version of this License issued under Section 6.1.
|
||||
For legal entities, "You" includes any entity which controls, is
|
||||
controlled by, or is under common control with You. For purposes of
|
||||
this definition, "control" means (a) the power, direct or indirect,
|
||||
to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (b) ownership of more than fifty percent
|
||||
(50%) of the outstanding shares or beneficial ownership of such
|
||||
entity.
|
||||
|
||||
2. Source Code License.
|
||||
|
||||
2.1. The Initial Developer Grant.
|
||||
The Initial Developer hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license, subject to third party intellectual property
|
||||
claims:
|
||||
(a) under intellectual property rights (other than patent or
|
||||
trademark) Licensable by Initial Developer to use, reproduce,
|
||||
modify, display, perform, sublicense and distribute the Original
|
||||
Code (or portions thereof) with or without Modifications, and/or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patents Claims infringed by the making, using or
|
||||
selling of Original Code, to make, have made, use, practice,
|
||||
sell, and offer for sale, and/or otherwise dispose of the
|
||||
Original Code (or portions thereof).
|
||||
|
||||
(c) the licenses granted in this Section 2.1(a) and (b) are
|
||||
effective on the date Initial Developer first distributes
|
||||
Original Code under the terms of this License.
|
||||
|
||||
(d) Notwithstanding Section 2.1(b) above, no patent license is
|
||||
granted: 1) for code that You delete from the Original Code; 2)
|
||||
separate from the Original Code; or 3) for infringements caused
|
||||
by: i) the modification of the Original Code or ii) the
|
||||
combination of the Original Code with other software or devices.
|
||||
|
||||
2.2. Contributor Grant.
|
||||
Subject to third party intellectual property claims, each Contributor
|
||||
hereby grants You a world-wide, royalty-free, non-exclusive license
|
||||
|
||||
(a) under intellectual property rights (other than patent or
|
||||
trademark) Licensable by Contributor, to use, reproduce, modify,
|
||||
display, perform, sublicense and distribute the Modifications
|
||||
created by such Contributor (or portions thereof) either on an
|
||||
unmodified basis, with other Modifications, as Covered Code
|
||||
and/or as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims infringed by the making, using, or
|
||||
selling of Modifications made by that Contributor either alone
|
||||
and/or in combination with its Contributor Version (or portions
|
||||
of such combination), to make, use, sell, offer for sale, have
|
||||
made, and/or otherwise dispose of: 1) Modifications made by that
|
||||
Contributor (or portions thereof); and 2) the combination of
|
||||
Modifications made by that Contributor with its Contributor
|
||||
Version (or portions of such combination).
|
||||
|
||||
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
|
||||
effective on the date Contributor first makes Commercial Use of
|
||||
the Covered Code.
|
||||
|
||||
(d) Notwithstanding Section 2.2(b) above, no patent license is
|
||||
granted: 1) for any code that Contributor has deleted from the
|
||||
Contributor Version; 2) separate from the Contributor Version;
|
||||
3) for infringements caused by: i) third party modifications of
|
||||
Contributor Version or ii) the combination of Modifications made
|
||||
by that Contributor with other software (except as part of the
|
||||
Contributor Version) or other devices; or 4) under Patent Claims
|
||||
infringed by Covered Code in the absence of Modifications made by
|
||||
that Contributor.
|
||||
|
||||
3. Distribution Obligations.
|
||||
|
||||
3.1. Application of License.
|
||||
The Modifications which You create or to which You contribute are
|
||||
governed by the terms of this License, including without limitation
|
||||
Section 2.2. The Source Code version of Covered Code may be
|
||||
distributed only under the terms of this License or a future version
|
||||
of this License released under Section 6.1, and You must include a
|
||||
copy of this License with every copy of the Source Code You
|
||||
distribute. You may not offer or impose any terms on any Source Code
|
||||
version that alters or restricts the applicable version of this
|
||||
License or the recipients' rights hereunder. However, You may include
|
||||
an additional document offering the additional rights described in
|
||||
Section 3.5.
|
||||
|
||||
3.2. Availability of Source Code.
|
||||
Any Modification which You create or to which You contribute must be
|
||||
made available in Source Code form under the terms of this License
|
||||
either on the same media as an Executable version or via an accepted
|
||||
Electronic Distribution Mechanism to anyone to whom you made an
|
||||
Executable version available; and if made available via Electronic
|
||||
Distribution Mechanism, must remain available for at least twelve (12)
|
||||
months after the date it initially became available, or at least six
|
||||
(6) months after a subsequent version of that particular Modification
|
||||
has been made available to such recipients. You are responsible for
|
||||
ensuring that the Source Code version remains available even if the
|
||||
Electronic Distribution Mechanism is maintained by a third party.
|
||||
|
||||
3.3. Description of Modifications.
|
||||
You must cause all Covered Code to which You contribute to contain a
|
||||
file documenting the changes You made to create that Covered Code and
|
||||
the date of any change. You must include a prominent statement that
|
||||
the Modification is derived, directly or indirectly, from Original
|
||||
Code provided by the Initial Developer and including the name of the
|
||||
Initial Developer in (a) the Source Code, and (b) in any notice in an
|
||||
Executable version or related documentation in which You describe the
|
||||
origin or ownership of the Covered Code.
|
||||
|
||||
3.4. Intellectual Property Matters
|
||||
(a) Third Party Claims.
|
||||
If Contributor has knowledge that a license under a third party's
|
||||
intellectual property rights is required to exercise the rights
|
||||
granted by such Contributor under Sections 2.1 or 2.2,
|
||||
Contributor must include a text file with the Source Code
|
||||
distribution titled "LEGAL" which describes the claim and the
|
||||
party making the claim in sufficient detail that a recipient will
|
||||
know whom to contact. If Contributor obtains such knowledge after
|
||||
the Modification is made available as described in Section 3.2,
|
||||
Contributor shall promptly modify the LEGAL file in all copies
|
||||
Contributor makes available thereafter and shall take other steps
|
||||
(such as notifying appropriate mailing lists or newsgroups)
|
||||
reasonably calculated to inform those who received the Covered
|
||||
Code that new knowledge has been obtained.
|
||||
|
||||
(b) Contributor APIs.
|
||||
If Contributor's Modifications include an application programming
|
||||
interface and Contributor has knowledge of patent licenses which
|
||||
are reasonably necessary to implement that API, Contributor must
|
||||
also include this information in the LEGAL file.
|
||||
|
||||
(c) Representations.
|
||||
Contributor represents that, except as disclosed pursuant to
|
||||
Section 3.4(a) above, Contributor believes that Contributor's
|
||||
Modifications are Contributor's original creation(s) and/or
|
||||
Contributor has sufficient rights to grant the rights conveyed by
|
||||
this License.
|
||||
|
||||
3.5. Required Notices.
|
||||
You must duplicate the notice in Exhibit A in each file of the Source
|
||||
Code. If it is not possible to put such notice in a particular Source
|
||||
Code file due to its structure, then You must include such notice in a
|
||||
location (such as a relevant directory) where a user would be likely
|
||||
to look for such a notice. If You created one or more Modification(s)
|
||||
You may add your name as a Contributor to the notice described in
|
||||
Exhibit A. You must also duplicate this License in any documentation
|
||||
for the Source Code where You describe recipients' rights or ownership
|
||||
rights relating to Covered Code. You may choose to offer, and to
|
||||
charge a fee for, warranty, support, indemnity or liability
|
||||
obligations to one or more recipients of Covered Code. However, You
|
||||
may do so only on Your own behalf, and not on behalf of the Initial
|
||||
Developer or any Contributor. You must make it absolutely clear than
|
||||
any such warranty, support, indemnity or liability obligation is
|
||||
offered by You alone, and You hereby agree to indemnify the Initial
|
||||
Developer and every Contributor for any liability incurred by the
|
||||
Initial Developer or such Contributor as a result of warranty,
|
||||
support, indemnity or liability terms You offer.
|
||||
|
||||
3.6. Distribution of Executable Versions.
|
||||
You may distribute Covered Code in Executable form only if the
|
||||
requirements of Section 3.1-3.5 have been met for that Covered Code,
|
||||
and if You include a notice stating that the Source Code version of
|
||||
the Covered Code is available under the terms of this License,
|
||||
including a description of how and where You have fulfilled the
|
||||
obligations of Section 3.2. The notice must be conspicuously included
|
||||
in any notice in an Executable version, related documentation or
|
||||
collateral in which You describe recipients' rights relating to the
|
||||
Covered Code. You may distribute the Executable version of Covered
|
||||
Code or ownership rights under a license of Your choice, which may
|
||||
contain terms different from this License, provided that You are in
|
||||
compliance with the terms of this License and that the license for the
|
||||
Executable version does not attempt to limit or alter the recipient's
|
||||
rights in the Source Code version from the rights set forth in this
|
||||
License. If You distribute the Executable version under a different
|
||||
license You must make it absolutely clear that any terms which differ
|
||||
from this License are offered by You alone, not by the Initial
|
||||
Developer or any Contributor. You hereby agree to indemnify the
|
||||
Initial Developer and every Contributor for any liability incurred by
|
||||
the Initial Developer or such Contributor as a result of any such
|
||||
terms You offer.
|
||||
|
||||
3.7. Larger Works.
|
||||
You may create a Larger Work by combining Covered Code with other code
|
||||
not governed by the terms of this License and distribute the Larger
|
||||
Work as a single product. In such a case, You must make sure the
|
||||
requirements of this License are fulfilled for the Covered Code.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation.
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Code due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description
|
||||
must be included in the LEGAL file described in Section 3.4 and must
|
||||
be included with all distributions of the Source Code. Except to the
|
||||
extent prohibited by statute or regulation, such description must be
|
||||
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||
understand it.
|
||||
|
||||
5. Application of this License.
|
||||
|
||||
This License applies to code to which the Initial Developer has
|
||||
attached the notice in Exhibit A and to related Covered Code.
|
||||
|
||||
6. Versions of the License.
|
||||
|
||||
6.1. New Versions.
|
||||
Netscape Communications Corporation ("Netscape") may publish revised
|
||||
and/or new versions of the License from time to time. Each version
|
||||
will be given a distinguishing version number.
|
||||
|
||||
6.2. Effect of New Versions.
|
||||
Once Covered Code has been published under a particular version of the
|
||||
License, You may always continue to use it under the terms of that
|
||||
version. You may also choose to use such Covered Code under the terms
|
||||
of any subsequent version of the License published by Netscape. No one
|
||||
other than Netscape has the right to modify the terms applicable to
|
||||
Covered Code created under this License.
|
||||
|
||||
6.3. Derivative Works.
|
||||
If You create or use a modified version of this License (which you may
|
||||
only do in order to apply it to code which is not already Covered Code
|
||||
governed by this License), You must (a) rename Your license so that
|
||||
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
|
||||
"MPL", "NPL" or any confusingly similar phrase do not appear in your
|
||||
license (except to note that your license differs from this License)
|
||||
and (b) otherwise make it clear that Your version of the license
|
||||
contains terms which differ from the Mozilla Public License and
|
||||
Netscape Public License. (Filling in the name of the Initial
|
||||
Developer, Original Code or Contributor in the notice described in
|
||||
Exhibit A shall not of themselves be deemed to be modifications of
|
||||
this License.)
|
||||
|
||||
7. DISCLAIMER OF WARRANTY.
|
||||
|
||||
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
||||
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
|
||||
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
|
||||
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
|
||||
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
|
||||
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
|
||||
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
|
||||
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
|
||||
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
|
||||
|
||||
8. TERMINATION.
|
||||
|
||||
8.1. This License and the rights granted hereunder will terminate
|
||||
automatically if You fail to comply with terms herein and fail to cure
|
||||
such breach within 30 days of becoming aware of the breach. All
|
||||
sublicenses to the Covered Code which are properly granted shall
|
||||
survive any termination of this License. Provisions which, by their
|
||||
nature, must remain in effect beyond the termination of this License
|
||||
shall survive.
|
||||
|
||||
8.2. If You initiate litigation by asserting a patent infringement
|
||||
claim (excluding declatory judgment actions) against Initial Developer
|
||||
or a Contributor (the Initial Developer or Contributor against whom
|
||||
You file such action is referred to as "Participant") alleging that:
|
||||
|
||||
(a) such Participant's Contributor Version directly or indirectly
|
||||
infringes any patent, then any and all rights granted by such
|
||||
Participant to You under Sections 2.1 and/or 2.2 of this License
|
||||
shall, upon 60 days notice from Participant terminate prospectively,
|
||||
unless if within 60 days after receipt of notice You either: (i)
|
||||
agree in writing to pay Participant a mutually agreeable reasonable
|
||||
royalty for Your past and future use of Modifications made by such
|
||||
Participant, or (ii) withdraw Your litigation claim with respect to
|
||||
the Contributor Version against such Participant. If within 60 days
|
||||
of notice, a reasonable royalty and payment arrangement are not
|
||||
mutually agreed upon in writing by the parties or the litigation claim
|
||||
is not withdrawn, the rights granted by Participant to You under
|
||||
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
|
||||
the 60 day notice period specified above.
|
||||
|
||||
(b) any software, hardware, or device, other than such Participant's
|
||||
Contributor Version, directly or indirectly infringes any patent, then
|
||||
any rights granted to You by such Participant under Sections 2.1(b)
|
||||
and 2.2(b) are revoked effective as of the date You first made, used,
|
||||
sold, distributed, or had made, Modifications made by that
|
||||
Participant.
|
||||
|
||||
8.3. If You assert a patent infringement claim against Participant
|
||||
alleging that such Participant's Contributor Version directly or
|
||||
indirectly infringes any patent where such claim is resolved (such as
|
||||
by license or settlement) prior to the initiation of patent
|
||||
infringement litigation, then the reasonable value of the licenses
|
||||
granted by such Participant under Sections 2.1 or 2.2 shall be taken
|
||||
into account in determining the amount or value of any payment or
|
||||
license.
|
||||
|
||||
8.4. In the event of termination under Sections 8.1 or 8.2 above,
|
||||
all end user license agreements (excluding distributors and resellers)
|
||||
which have been validly granted by You or any distributor hereunder
|
||||
prior to termination shall survive termination.
|
||||
|
||||
9. LIMITATION OF LIABILITY.
|
||||
|
||||
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
|
||||
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
|
||||
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
|
||||
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
|
||||
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
|
||||
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
|
||||
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
|
||||
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
|
||||
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
|
||||
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
|
||||
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
|
||||
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
|
||||
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
|
||||
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
10. U.S. GOVERNMENT END USERS.
|
||||
|
||||
The Covered Code is a "commercial item," as that term is defined in
|
||||
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
|
||||
software" and "commercial computer software documentation," as such
|
||||
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
|
||||
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
|
||||
all U.S. Government End Users acquire Covered Code with only those
|
||||
rights set forth herein.
|
||||
|
||||
11. MISCELLANEOUS.
|
||||
|
||||
This License represents the complete agreement concerning subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. This License shall be governed by
|
||||
California law provisions (except to the extent applicable law, if
|
||||
any, provides otherwise), excluding its conflict-of-law provisions.
|
||||
With respect to disputes in which at least one party is a citizen of,
|
||||
or an entity chartered or registered to do business in the United
|
||||
States of America, any litigation relating to this License shall be
|
||||
subject to the jurisdiction of the Federal Courts of the Northern
|
||||
District of California, with venue lying in Santa Clara County,
|
||||
California, with the losing party responsible for costs, including
|
||||
without limitation, court costs and reasonable attorneys' fees and
|
||||
expenses. The application of the United Nations Convention on
|
||||
Contracts for the International Sale of Goods is expressly excluded.
|
||||
Any law or regulation which provides that the language of a contract
|
||||
shall be construed against the drafter shall not apply to this
|
||||
License.
|
||||
|
||||
12. RESPONSIBILITY FOR CLAIMS.
|
||||
|
||||
As between Initial Developer and the Contributors, each party is
|
||||
responsible for claims and damages arising, directly or indirectly,
|
||||
out of its utilization of rights under this License and You agree to
|
||||
work with Initial Developer and Contributors to distribute such
|
||||
responsibility on an equitable basis. Nothing herein is intended or
|
||||
shall be deemed to constitute any admission of liability.
|
||||
|
||||
13. MULTIPLE-LICENSED CODE.
|
||||
|
||||
Initial Developer may designate portions of the Covered Code as
|
||||
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
|
||||
Developer permits you to utilize portions of the Covered Code under
|
||||
Your choice of the NPL or the alternative licenses, if any, specified
|
||||
by the Initial Developer in the file described in Exhibit A.
|
||||
|
||||
EXHIBIT A -Mozilla Public License.
|
||||
|
||||
``The contents of this file are subject to the Mozilla Public License
|
||||
Version 1.1 (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.mozilla.org/MPL/
|
||||
|
||||
Software distributed under the License is distributed on an "AS IS"
|
||||
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing rights and limitations
|
||||
under the License.
|
||||
|
||||
The Original Code is ______________________________________.
|
||||
|
||||
The Initial Developer of the Original Code is ________________________.
|
||||
Portions created by ______________________ are Copyright (C) ______
|
||||
_______________________. All Rights Reserved.
|
||||
|
||||
Contributor(s): ______________________________________.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms
|
||||
of the _____ license (the "[___] License"), in which case the
|
||||
provisions of [______] License are applicable instead of those
|
||||
above. If you wish to allow use of your version of this file only
|
||||
under the terms of the [____] License and not to allow others to use
|
||||
your version of this file under the MPL, indicate your decision by
|
||||
deleting the provisions above and replace them with the notice and
|
||||
other provisions required by the [___] License. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file
|
||||
under either the MPL or the [___] License."
|
||||
|
||||
[NOTE: The text of this Exhibit A may differ slightly from the text of
|
||||
the notices in the Source Code files of the Original Code. You should
|
||||
use the text of this Exhibit A rather than the text found in the
|
||||
Original Code Source Code for Your Modifications.]
|
||||
|
78
protocols/ssh/Makefile.am
Normal file
78
protocols/ssh/Makefile.am
Normal file
@ -0,0 +1,78 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is libguac-client-ssh.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Michael Jumper.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
lib_LTLIBRARIES = libguac-client-ssh.la
|
||||
|
||||
libguac_client_ssh_la_SOURCES = \
|
||||
src/blank.c \
|
||||
src/buffer.c \
|
||||
src/char_mappings.c \
|
||||
src/client.c \
|
||||
src/common.c \
|
||||
src/cursor.c \
|
||||
src/display.c \
|
||||
src/guac_handlers.c \
|
||||
src/ibar.c \
|
||||
src/ssh_client.c \
|
||||
src/terminal.c \
|
||||
src/terminal_handlers.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
include/blank.h \
|
||||
include/buffer.h \
|
||||
include/char_mappings.h \
|
||||
include/client.h \
|
||||
include/common.h \
|
||||
include/cursor.h \
|
||||
include/display.h \
|
||||
include/guac_handlers.h \
|
||||
include/ibar.h \
|
||||
include/libssh_compat.h \
|
||||
include/ssh_client.h \
|
||||
include/terminal.h \
|
||||
include/terminal_handlers.h \
|
||||
include/types.h
|
||||
|
||||
libguac_client_ssh_la_CFLAGS = -Werror -Wall -pedantic -Iinclude @PANGO_CFLAGS@ @PANGOCAIRO_CFLAGS@
|
||||
libguac_client_ssh_la_LIBADD = @PANGO_LIBS@ @PANGOCAIRO_LIBS@
|
||||
libguac_client_ssh_la_LDFLAGS = -version-info 0:0:0
|
||||
|
||||
EXTRA_DIST = LICENSE
|
||||
|
74
protocols/ssh/README
Normal file
74
protocols/ssh/README
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
------------------------------------------------------------
|
||||
About this README
|
||||
------------------------------------------------------------
|
||||
|
||||
This README is intended to provide quick and to-the-point documentation for
|
||||
technical users intending to compile parts of Guacamole themselves.
|
||||
|
||||
Distribution-specific packages are available from the files section of the main
|
||||
project page:
|
||||
|
||||
http://sourceforge.net/projects/guacamole/files/
|
||||
|
||||
Distribution-specific documentation is provided on the Guacamole wiki:
|
||||
|
||||
http://guac-dev.org/
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
What is libguac-client-ssh?
|
||||
------------------------------------------------------------
|
||||
|
||||
libguac-client-ssh is a protocol support plugin for the Guacamole proxy (guacd)
|
||||
which provides support for SSH, the secure shell.
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
Compiling and installing libguac-client-ssh
|
||||
------------------------------------------------------------
|
||||
|
||||
Please note that distribution-specific pre-compiled packages are available from
|
||||
the files section of the main project site:
|
||||
|
||||
http://sourceforge.net/projects/guacamole/files/
|
||||
|
||||
libguac-client-ssh is built using the popular GNU Automake, and thus provides
|
||||
the standard configure script.
|
||||
|
||||
1) Run configure
|
||||
|
||||
$ ./configure
|
||||
|
||||
Assuming all dependencies have been installed, this should succeed without
|
||||
errors.
|
||||
|
||||
2) Run make
|
||||
|
||||
$ make
|
||||
|
||||
libguac-client-ssh will now compile.
|
||||
|
||||
3) Install (as root)
|
||||
|
||||
# make install
|
||||
|
||||
libguac-client-ssh will install to your /usr/local/lib directory by default.
|
||||
You can change the install location by using the --prefix option for
|
||||
configure.
|
||||
|
||||
You will need to run ldconfig (as root) so that guacd can find the library
|
||||
when needed:
|
||||
|
||||
# ldconfig
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
Reporting problems
|
||||
------------------------------------------------------------
|
||||
|
||||
Please report any bugs encountered by opening a new ticket at the Trac system
|
||||
hosted at:
|
||||
|
||||
http://guac-dev.org/trac/
|
||||
|
66
protocols/ssh/configure.in
Normal file
66
protocols/ssh/configure.in
Normal file
@ -0,0 +1,66 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is libguac-client-ssh.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Michael Jumper.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
AC_INIT(src/client.c)
|
||||
AM_INIT_AUTOMAKE([libguac-client-ssh], 0.8.0)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([guac], [guac_client_plugin_open],, AC_MSG_ERROR("libguac must be installed first"))
|
||||
AC_CHECK_LIB([cairo], [cairo_create],, AC_MSG_ERROR("cairo is required for drawing instructions"))
|
||||
AC_CHECK_LIB([ssh], [ssh_new],, AC_MSG_ERROR("libssh is required"))
|
||||
AC_CHECK_LIB([pthread], [pthread_create])
|
||||
PKG_CHECK_MODULES([PANGO], pango);
|
||||
PKG_CHECK_MODULES([PANGOCAIRO], pangocairo);
|
||||
|
||||
# Check for SSH functions
|
||||
AC_CHECK_FUNC(ssh_channel_close, AC_DEFINE(HAVE_SSH_CHANNEL_CLOSE))
|
||||
AC_CHECK_FUNC(ssh_channel_send_eof, AC_DEFINE(HAVE_SSH_CHANNEL_SEND_EOF))
|
||||
AC_CHECK_FUNC(ssh_channel_free, AC_DEFINE(HAVE_SSH_CHANNEL_FREE))
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([guacamole/client.h guacamole/guacio.h guacamole/protocol.h])
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_MALLOC
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
52
protocols/ssh/include/blank.h
Normal file
52
protocols/ssh/include/blank.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _GUAC_SSH_BLANK_H
|
||||
#define _GUAC_SSH_BLANK_H
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
|
||||
/**
|
||||
* Creates a new blank cursor, returning the corresponding cursor object.
|
||||
*
|
||||
* @param client The guac_client to send the cursor to.
|
||||
* @return A new cursor which must be free'd via guac_ssh_cursor_free()/
|
||||
*/
|
||||
guac_ssh_cursor* guac_ssh_create_blank(guac_client* client);
|
||||
|
||||
#endif
|
144
protocols/ssh/include/buffer.h
Normal file
144
protocols/ssh/include/buffer.h
Normal file
@ -0,0 +1,144 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_BUFFER_H
|
||||
#define _SSH_GUAC_BUFFER_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/**
|
||||
* A single variable-length row of terminal data.
|
||||
*/
|
||||
typedef struct guac_terminal_buffer_row {
|
||||
|
||||
/**
|
||||
* Array of guac_terminal_char representing the contents of the row.
|
||||
*/
|
||||
guac_terminal_char* characters;
|
||||
|
||||
/**
|
||||
* The length of this row in characters. This is the number of initialized
|
||||
* characters in the buffer, usually equal to the number of characters
|
||||
* in the screen width at the time this row was created.
|
||||
*/
|
||||
int length;
|
||||
|
||||
/**
|
||||
* The number of elements in the characters array. After the length
|
||||
* equals this value, the array must be resized.
|
||||
*/
|
||||
int available;
|
||||
|
||||
} guac_terminal_buffer_row;
|
||||
|
||||
/**
|
||||
* A buffer containing a constant number of arbitrary-length rows.
|
||||
* New rows can be appended to the buffer, with the oldest row replaced with
|
||||
* the new row.
|
||||
*/
|
||||
typedef struct guac_terminal_buffer {
|
||||
|
||||
/**
|
||||
* The character to assign to newly-allocated cells.
|
||||
*/
|
||||
guac_terminal_char default_character;
|
||||
|
||||
/**
|
||||
* Array of buffer rows. This array functions as a ring buffer.
|
||||
* When a new row needs to be appended, the top reference is moved down
|
||||
* and the old top row is replaced.
|
||||
*/
|
||||
guac_terminal_buffer_row* rows;
|
||||
|
||||
/**
|
||||
* The row to replace when adding a new row to the buffer.
|
||||
*/
|
||||
int top;
|
||||
|
||||
/**
|
||||
* The number of rows currently stored in the buffer.
|
||||
*/
|
||||
int length;
|
||||
|
||||
/**
|
||||
* The number of rows in the buffer. This is the total capacity
|
||||
* of the buffer.
|
||||
*/
|
||||
int available;
|
||||
|
||||
} guac_terminal_buffer;
|
||||
|
||||
/**
|
||||
* Allocates a new buffer having the given maximum number of rows. New character cells will
|
||||
* be initialized to the given character.
|
||||
*/
|
||||
guac_terminal_buffer* guac_terminal_buffer_alloc(int rows, guac_terminal_char* default_character);
|
||||
|
||||
/**
|
||||
* Frees the given buffer.
|
||||
*/
|
||||
void guac_terminal_buffer_free(guac_terminal_buffer* buffer);
|
||||
|
||||
/**
|
||||
* Returns the row at the given location. The row returned is guaranteed to be at least the given
|
||||
* width.
|
||||
*/
|
||||
guac_terminal_buffer_row* guac_terminal_buffer_get_row(guac_terminal_buffer* buffer, int row, int width);
|
||||
|
||||
/**
|
||||
* Copies the given range of columns to a new location, offset from
|
||||
* the original by the given number of columns.
|
||||
*/
|
||||
void guac_terminal_buffer_copy_columns(guac_terminal_buffer* buffer, int row,
|
||||
int start_column, int end_column, int offset);
|
||||
|
||||
/**
|
||||
* Copies the given range of rows to a new location, offset from the
|
||||
* original by the given number of rows.
|
||||
*/
|
||||
void guac_terminal_buffer_copy_rows(guac_terminal_buffer* buffer,
|
||||
int start_row, int end_row, int offset);
|
||||
|
||||
/**
|
||||
* Sets the given range of columns within the given row to the given
|
||||
* character.
|
||||
*/
|
||||
void guac_terminal_buffer_set_columns(guac_terminal_buffer* buffer, int row,
|
||||
int start_column, int end_column, guac_terminal_char* character);
|
||||
|
||||
#endif
|
||||
|
63
protocols/ssh/include/char_mappings.h
Normal file
63
protocols/ssh/include/char_mappings.h
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _GUAC_SSH_CHAR_MAPPINGS_H
|
||||
#define _GUAC_SSH_CHAR_MAPPINGS_H
|
||||
|
||||
/**
|
||||
* VT100 graphics mapping. Each entry is the corresponding Unicode codepoint
|
||||
* for the character N+32, where N is the index of the element in the array.
|
||||
* All characters less than 32 are universally mapped to themselves.
|
||||
*/
|
||||
extern const int vt100_map[];
|
||||
|
||||
/**
|
||||
* Null graphics mapping. Each entry is the corresponding Unicode codepoint
|
||||
* for the character N+32, where N is the index of the element in the array.
|
||||
* All characters less than 32 are universally mapped to themselves.
|
||||
*/
|
||||
extern const int null_map[];
|
||||
|
||||
/**
|
||||
* User graphics mapping. Each entry is the corresponding Unicode codepoint
|
||||
* for the character N+32, where N is the index of the element in the array.
|
||||
* All characters less than 32 are universally mapped to themselves.
|
||||
*/
|
||||
extern const int user_map[];
|
||||
|
||||
#endif
|
||||
|
146
protocols/ssh/include/client.h
Normal file
146
protocols/ssh/include/client.h
Normal file
@ -0,0 +1,146 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Muehlner <dagger10k@users.sourceforge.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_CLIENT_H
|
||||
#define _SSH_GUAC_CLIENT_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
#include "terminal.h"
|
||||
#include "cursor.h"
|
||||
|
||||
/**
|
||||
* SSH-specific client data.
|
||||
*/
|
||||
typedef struct ssh_guac_client_data {
|
||||
|
||||
/**
|
||||
* The hostname of the SSH server to connect to.
|
||||
*/
|
||||
char hostname[1024];
|
||||
|
||||
/**
|
||||
* The port of the SSH server to connect to.
|
||||
*/
|
||||
int port;
|
||||
|
||||
/**
|
||||
* The name of the user to login as.
|
||||
*/
|
||||
char username[1024];
|
||||
|
||||
/**
|
||||
* The password to give when authenticating.
|
||||
*/
|
||||
char password[1024];
|
||||
|
||||
/**
|
||||
* The name of the font to use for display rendering.
|
||||
*/
|
||||
char font_name[1024];
|
||||
|
||||
/**
|
||||
* The size of the font to use, in points.
|
||||
*/
|
||||
int font_size;
|
||||
|
||||
/**
|
||||
* The SSH client thread.
|
||||
*/
|
||||
pthread_t client_thread;
|
||||
|
||||
/**
|
||||
* SSH session, used by the SSH client thread.
|
||||
*/
|
||||
ssh_session session;
|
||||
|
||||
/**
|
||||
* SSH terminal channel, used by the SSH client thread.
|
||||
*/
|
||||
ssh_channel term_channel;
|
||||
|
||||
/**
|
||||
* The terminal which will render all output from the SSH client.
|
||||
*/
|
||||
guac_terminal* term;
|
||||
|
||||
/**
|
||||
* The current contents of the clipboard.
|
||||
*/
|
||||
char* clipboard_data;
|
||||
|
||||
/**
|
||||
* Whether the alt key is currently being held down.
|
||||
*/
|
||||
int mod_alt;
|
||||
|
||||
/**
|
||||
* Whether the control key is currently being held down.
|
||||
*/
|
||||
int mod_ctrl;
|
||||
|
||||
/**
|
||||
* Whether the shift key is currently being held down.
|
||||
*/
|
||||
int mod_shift;
|
||||
|
||||
/**
|
||||
* The current mouse button state.
|
||||
*/
|
||||
int mouse_mask;
|
||||
|
||||
/**
|
||||
* The cached I-bar cursor.
|
||||
*/
|
||||
guac_ssh_cursor* ibar_cursor;
|
||||
|
||||
/**
|
||||
* The cached invisible (blank) cursor.
|
||||
*/
|
||||
guac_ssh_cursor* blank_cursor;
|
||||
|
||||
/**
|
||||
* The current cursor, used to avoid re-setting the cursor.
|
||||
*/
|
||||
guac_ssh_cursor* current_cursor;
|
||||
|
||||
} ssh_guac_client_data;
|
||||
|
||||
#endif
|
||||
|
68
protocols/ssh/include/common.h
Normal file
68
protocols/ssh/include/common.h
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_COMMON_H
|
||||
#define _SSH_GUAC_COMMON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* Returns the closest value to the value given that is also
|
||||
* within the given range.
|
||||
*/
|
||||
int guac_terminal_fit_to_range(int value, int min, int max);
|
||||
|
||||
/**
|
||||
* Encodes the given codepoint as UTF-8, storing the result within the
|
||||
* provided buffer, and returning the number of bytes stored.
|
||||
*/
|
||||
int guac_terminal_encode_utf8(int codepoint, char* utf8);
|
||||
|
||||
/**
|
||||
* Returns whether a codepoint has a corresponding glyph, or is rendered
|
||||
* as a blank space.
|
||||
*/
|
||||
bool guac_terminal_has_glyph(int codepoint);
|
||||
|
||||
/**
|
||||
* Similar to write, but automatically retries the write operation until
|
||||
* an error occurs.
|
||||
*/
|
||||
int guac_terminal_write_all(int fd, const char* buffer, int size);
|
||||
|
||||
#endif
|
||||
|
89
protocols/ssh/include/cursor.h
Normal file
89
protocols/ssh/include/cursor.h
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _GUAC_SSH_CURSOR_H
|
||||
#define _GUAC_SSH_CURSOR_H
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
typedef struct guac_ssh_cursor {
|
||||
|
||||
/**
|
||||
* A buffer allocated with guac_client_alloc_buffer() that contains the
|
||||
* cursor image.
|
||||
*/
|
||||
guac_layer* buffer;
|
||||
|
||||
/**
|
||||
* The width of the cursor in pixels.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of the cursor in pixels.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* The X coordinate of the cursor hotspot.
|
||||
*/
|
||||
int hotspot_x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the cursor hotspot.
|
||||
*/
|
||||
int hotspot_y;
|
||||
|
||||
} guac_ssh_cursor;
|
||||
|
||||
/**
|
||||
* Allocates a new cursor, pre-populating the cursor with a newly-allocated
|
||||
* buffer.
|
||||
*/
|
||||
guac_ssh_cursor* guac_ssh_cursor_alloc(guac_client* client);
|
||||
|
||||
/**
|
||||
* Frees the buffer associated with this cursor as well as the cursor itself.
|
||||
*/
|
||||
void guac_ssh_cursor_free(guac_client* client, guac_ssh_cursor* cursor);
|
||||
|
||||
/**
|
||||
* Set the remote cursor.
|
||||
*/
|
||||
void guac_ssh_set_cursor(guac_client* client, guac_ssh_cursor* cursor);
|
||||
|
||||
#endif
|
293
protocols/ssh/include/display.h
Normal file
293
protocols/ssh/include/display.h
Normal file
@ -0,0 +1,293 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_DISPLAY_H
|
||||
#define _SSH_GUAC_DISPLAY_H
|
||||
|
||||
#include <pango/pangocairo.h>
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/**
|
||||
* The available color palette. All integer colors within structures
|
||||
* here are indices into this palette.
|
||||
*/
|
||||
extern const guac_terminal_color guac_terminal_palette[16];
|
||||
|
||||
/**
|
||||
* All available terminal operations which affect character cells.
|
||||
*/
|
||||
typedef enum guac_terminal_operation_type {
|
||||
|
||||
/**
|
||||
* Operation which does nothing.
|
||||
*/
|
||||
GUAC_CHAR_NOP,
|
||||
|
||||
/**
|
||||
* Operation which copies a character from a given row/column coordinate.
|
||||
*/
|
||||
GUAC_CHAR_COPY,
|
||||
|
||||
/**
|
||||
* Operation which sets the character and attributes.
|
||||
*/
|
||||
GUAC_CHAR_SET
|
||||
|
||||
} guac_terminal_operation_type;
|
||||
|
||||
/**
|
||||
* A pairing of a guac_terminal_operation_type and all parameters required by
|
||||
* that operation type.
|
||||
*/
|
||||
typedef struct guac_terminal_operation {
|
||||
|
||||
/**
|
||||
* The type of operation to perform.
|
||||
*/
|
||||
guac_terminal_operation_type type;
|
||||
|
||||
/**
|
||||
* The character (and attributes) to set the current location to. This is
|
||||
* only applicable to GUAC_CHAR_SET.
|
||||
*/
|
||||
guac_terminal_char character;
|
||||
|
||||
/**
|
||||
* The row to copy a character from. This is only applicable to
|
||||
* GUAC_CHAR_COPY.
|
||||
*/
|
||||
int row;
|
||||
|
||||
/**
|
||||
* The column to copy a character from. This is only applicable to
|
||||
* GUAC_CHAR_COPY.
|
||||
*/
|
||||
int column;
|
||||
|
||||
} guac_terminal_operation;
|
||||
|
||||
|
||||
/**
|
||||
* A cached glyph.
|
||||
*/
|
||||
typedef struct guac_terminal_glyph {
|
||||
|
||||
/**
|
||||
* The location within the glyph layer that this glyph can be found.
|
||||
*/
|
||||
int location;
|
||||
|
||||
/**
|
||||
* The codepoint currently stored at that location.
|
||||
*/
|
||||
int codepoint;
|
||||
|
||||
} guac_terminal_glyph;
|
||||
|
||||
|
||||
/**
|
||||
* Set of all pending operations for the currently-visible screen area.
|
||||
*/
|
||||
typedef struct guac_terminal_display {
|
||||
|
||||
/**
|
||||
* The Guacamole client this display will use for rendering.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* Array of all operations pending for the visible screen area.
|
||||
*/
|
||||
guac_terminal_operation* operations;
|
||||
|
||||
/**
|
||||
* The width of the screen, in characters.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of the screen, in characters.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* The description of the font to use for rendering.
|
||||
*/
|
||||
PangoFontDescription* font_desc;
|
||||
|
||||
/**
|
||||
* The width of each character, in pixels.
|
||||
*/
|
||||
int char_width;
|
||||
|
||||
/**
|
||||
* The height of each character, in pixels.
|
||||
*/
|
||||
int char_height;
|
||||
|
||||
/**
|
||||
* Index of next glyph to create
|
||||
*/
|
||||
int next_glyph;
|
||||
|
||||
/**
|
||||
* Index of locations for each glyph in the stroke and fill layers.
|
||||
*/
|
||||
guac_terminal_glyph glyphs[512];
|
||||
|
||||
/**
|
||||
* Color of glyphs in copy buffer
|
||||
*/
|
||||
int glyph_foreground;
|
||||
|
||||
/**
|
||||
* Color of glyphs in copy buffer
|
||||
*/
|
||||
int glyph_background;
|
||||
|
||||
/**
|
||||
* Layer above default layer which highlights selected text.
|
||||
*/
|
||||
guac_layer* select_layer;
|
||||
|
||||
/**
|
||||
* A single wide layer holding each glyph, with each glyph only
|
||||
* colored with foreground color (background remains transparent).
|
||||
*/
|
||||
guac_layer* glyph_stroke;
|
||||
|
||||
/**
|
||||
* A single wide layer holding each glyph, with each glyph properly
|
||||
* colored with foreground and background color (no transparency at all).
|
||||
*/
|
||||
guac_layer* filled_glyphs;
|
||||
|
||||
/**
|
||||
* Whether text is being selected.
|
||||
*/
|
||||
bool text_selected;
|
||||
|
||||
/**
|
||||
* Whether the selection is finished, and will no longer be modified. A
|
||||
* committed selection remains highlighted for reference, but the
|
||||
* highlight will be removed when the display changes.
|
||||
*/
|
||||
bool selection_committed;
|
||||
|
||||
/**
|
||||
* The row that the selection starts at.
|
||||
*/
|
||||
int selection_start_row;
|
||||
|
||||
/**
|
||||
* The column that the selection starts at.
|
||||
*/
|
||||
int selection_start_column;
|
||||
|
||||
/**
|
||||
* The row that the selection ends at.
|
||||
*/
|
||||
int selection_end_row;
|
||||
|
||||
/**
|
||||
* The column that the selection ends at.
|
||||
*/
|
||||
int selection_end_column;
|
||||
|
||||
|
||||
} guac_terminal_display;
|
||||
|
||||
/**
|
||||
* Allocates a new display having the given default foreground and background
|
||||
* colors.
|
||||
*/
|
||||
guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
|
||||
const char* font_name, int font_size,
|
||||
int foreground, int background);
|
||||
|
||||
/**
|
||||
* Frees the given display.
|
||||
*/
|
||||
void guac_terminal_display_free(guac_terminal_display* display);
|
||||
|
||||
/**
|
||||
* Copies the given range of columns to a new location, offset from
|
||||
* the original by the given number of columns.
|
||||
*/
|
||||
void guac_terminal_display_copy_columns(guac_terminal_display* display, int row,
|
||||
int start_column, int end_column, int offset);
|
||||
|
||||
/**
|
||||
* Copies the given range of rows to a new location, offset from the
|
||||
* original by the given number of rows.
|
||||
*/
|
||||
void guac_terminal_display_copy_rows(guac_terminal_display* display,
|
||||
int start_row, int end_row, int offset);
|
||||
|
||||
/**
|
||||
* Sets the given range of columns within the given row to the given
|
||||
* character.
|
||||
*/
|
||||
void guac_terminal_display_set_columns(guac_terminal_display* display, int row,
|
||||
int start_column, int end_column, guac_terminal_char* character);
|
||||
|
||||
/**
|
||||
* Resize the terminal to the given dimensions.
|
||||
*/
|
||||
void guac_terminal_display_resize(guac_terminal_display* display, int width, int height);
|
||||
|
||||
/**
|
||||
* Flushes all pending operations within the given guac_terminal_display.
|
||||
*/
|
||||
void guac_terminal_display_flush(guac_terminal_display* display);
|
||||
|
||||
/**
|
||||
* Draws the text selection rectangle from the given coordinates to the given end coordinates.
|
||||
*/
|
||||
void guac_terminal_display_select(guac_terminal_display* display,
|
||||
int start_row, int start_col, int end_row, int end_col);
|
||||
|
||||
/**
|
||||
* Commits the select rectangle, allowing the display to clear it when
|
||||
* necessary.
|
||||
*/
|
||||
void guac_terminal_display_commit_select(guac_terminal_display* display);
|
||||
|
||||
#endif
|
||||
|
52
protocols/ssh/include/guac_handlers.h
Normal file
52
protocols/ssh/include/guac_handlers.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Muehlner <dagger10k@users.sourceforge.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_HANDLERS_H
|
||||
#define _SSH_GUAC_HANDLERS_H
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
int ssh_guac_client_handle_messages(guac_client* client);
|
||||
int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed);
|
||||
int ssh_guac_client_mouse_handler(guac_client* client, int x, int y, int mask);
|
||||
int ssh_guac_client_clipboard_handler(guac_client* client, char* data);
|
||||
int ssh_guac_client_size_handler(guac_client* client, int width, int height);
|
||||
int ssh_guac_client_free_handler(guac_client* client);
|
||||
|
||||
#endif
|
||||
|
77
protocols/ssh/include/ibar.h
Normal file
77
protocols/ssh/include/ibar.h
Normal file
@ -0,0 +1,77 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _GUAC_SSH_IBAR_H
|
||||
#define _GUAC_SSH_IBAR_H
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
|
||||
/**
|
||||
* Width of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_ssh_ibar_width;
|
||||
|
||||
/**
|
||||
* Height of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_ssh_ibar_height;
|
||||
|
||||
/**
|
||||
* Number of bytes in each row of the embedded mouse cursor graphic.
|
||||
*/
|
||||
extern const int guac_ssh_ibar_stride;
|
||||
|
||||
/**
|
||||
* The Cairo grapic format of the mouse cursor graphic.
|
||||
*/
|
||||
extern const cairo_format_t guac_ssh_ibar_format;
|
||||
|
||||
/**
|
||||
* Embedded mouse cursor graphic.
|
||||
*/
|
||||
extern unsigned char guac_ssh_ibar[];
|
||||
|
||||
/**
|
||||
* Creates a new I-bar cursor, returning the corresponding cursor object.
|
||||
*
|
||||
* @param client The guac_client to send the cursor to.
|
||||
* @return A new cursor which must be free'd via guac_ssh_cursor_free()/
|
||||
*/
|
||||
guac_ssh_cursor* guac_ssh_create_ibar(guac_client* client);
|
||||
|
||||
#endif
|
57
protocols/ssh/include/libssh_compat.h
Normal file
57
protocols/ssh/include/libssh_compat.h
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_LIBSSH_COMPAT_H
|
||||
#define _SSH_GUAC_LIBSSH_COMPAT_H
|
||||
|
||||
/* Define ssh_channel_close() if undefined */
|
||||
#ifndef HAVE_SSH_CHANNEL_CLOSE
|
||||
#define ssh_channel_close channel_close
|
||||
#endif
|
||||
|
||||
/* Define ssh_channel_send_eof() if undefined */
|
||||
#ifndef HAVE_SSH_CHANNEL_SEND_EOF
|
||||
#define ssh_channel_send_eof channel_send_eof
|
||||
#endif
|
||||
|
||||
/* Define ssh_channel_free() if undefined */
|
||||
#ifndef HAVE_SSH_CHANNEL_FREE
|
||||
#define ssh_channel_free channel_free
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
49
protocols/ssh/include/ssh_client.h
Normal file
49
protocols/ssh/include/ssh_client.h
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __SSH_CLIENT_H
|
||||
#define __SSH_CLIENT_H
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
/**
|
||||
* Main SSH client thread, handling transfer of SSH output to STDOUT.
|
||||
*/
|
||||
void* ssh_client_thread(void* data);
|
||||
|
||||
#endif
|
||||
|
419
protocols/ssh/include/terminal.h
Normal file
419
protocols/ssh/include/terminal.h
Normal file
@ -0,0 +1,419 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_TERMINAL_H
|
||||
#define _SSH_GUAC_TERMINAL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "display.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/**
|
||||
* The maximum number of custom tab stops.
|
||||
*/
|
||||
#define GUAC_TERMINAL_MAX_TABS 16
|
||||
|
||||
/**
|
||||
* The number of rows to scroll per scroll wheel event.
|
||||
*/
|
||||
#define GUAC_SSH_WHEEL_SCROLL_AMOUNT 3
|
||||
|
||||
typedef struct guac_terminal guac_terminal;
|
||||
|
||||
/**
|
||||
* Handler for characters printed to the terminal. When a character is printed,
|
||||
* the current char handler for the terminal is called and given that
|
||||
* character.
|
||||
*/
|
||||
typedef int guac_terminal_char_handler(guac_terminal* term, char c);
|
||||
|
||||
/**
|
||||
* Represents a terminal emulator which uses a given Guacamole client to
|
||||
* render itself.
|
||||
*/
|
||||
struct guac_terminal {
|
||||
|
||||
/**
|
||||
* The Guacamole client this terminal emulator will use for rendering.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* Lock which restricts simultaneous access to this terminal via the root
|
||||
* guac_terminal_* functions.
|
||||
*/
|
||||
pthread_mutex_t lock;
|
||||
|
||||
/**
|
||||
* Pipe which should be written to (and read from) to provide output to
|
||||
* this terminal. Another thread should read from this pipe when writing
|
||||
* data to the terminal. It would make sense for the terminal to provide
|
||||
* this thread, but for simplicity, that logic is left to the guac
|
||||
* message handler (to give the message handler something to block with).
|
||||
*/
|
||||
int stdout_pipe_fd[2];
|
||||
|
||||
/**
|
||||
* Pipe which will be the source of user input. When a terminal code
|
||||
* generates synthesized user input, that data will be written to
|
||||
* this pipe.
|
||||
*/
|
||||
int stdin_pipe_fd[2];
|
||||
|
||||
/**
|
||||
* The relative offset of the display. A positive value indicates that
|
||||
* many rows have been scrolled into view, zero indicates that no
|
||||
* scrolling has occurred. Negative values are illegal.
|
||||
*/
|
||||
int scroll_offset;
|
||||
|
||||
/**
|
||||
* The width of the terminal, in characters.
|
||||
*/
|
||||
int term_width;
|
||||
|
||||
/**
|
||||
* The height of the terminal, in characters.
|
||||
*/
|
||||
int term_height;
|
||||
|
||||
/**
|
||||
* The index of the first row in the scrolling region.
|
||||
*/
|
||||
int scroll_start;
|
||||
|
||||
/**
|
||||
* The index of the last row in the scrolling region.
|
||||
*/
|
||||
int scroll_end;
|
||||
|
||||
/**
|
||||
* The current row location of the cursor.
|
||||
*/
|
||||
int cursor_row;
|
||||
|
||||
/**
|
||||
* The current column location of the cursor.
|
||||
*/
|
||||
int cursor_col;
|
||||
|
||||
/**
|
||||
* The row of the rendered cursor.
|
||||
*/
|
||||
int visible_cursor_row;
|
||||
|
||||
/**
|
||||
* The column of the rendered cursor.
|
||||
*/
|
||||
int visible_cursor_col;
|
||||
|
||||
/**
|
||||
* The row of the saved cursor (ESC 7).
|
||||
*/
|
||||
int saved_cursor_row;
|
||||
|
||||
/**
|
||||
* The column of the saved cursor (ESC 7).
|
||||
*/
|
||||
int saved_cursor_col;
|
||||
|
||||
/**
|
||||
* The attributes which will be applied to future characters.
|
||||
*/
|
||||
guac_terminal_attributes current_attributes;
|
||||
|
||||
/**
|
||||
* The character whose attributes dictate the default attributes
|
||||
* of all characters. When new screen space is allocated, this
|
||||
* character fills the gaps.
|
||||
*/
|
||||
guac_terminal_char default_char;
|
||||
|
||||
/**
|
||||
* Handler which will receive all printed characters, updating the terminal
|
||||
* accordingly.
|
||||
*/
|
||||
guac_terminal_char_handler* char_handler;
|
||||
|
||||
/**
|
||||
* The difference between the currently-rendered screen and the current
|
||||
* state of the terminal.
|
||||
*/
|
||||
guac_terminal_display* display;
|
||||
|
||||
/**
|
||||
* Current terminal display state. All characters present on the screen
|
||||
* are within this buffer. This has nothing to do with the display, which
|
||||
* facilitates transfer of a set of changes to the remote display.
|
||||
*/
|
||||
guac_terminal_buffer* buffer;
|
||||
|
||||
/**
|
||||
* Automatically place a tabstop every N characters. If zero, then no
|
||||
* tabstops exist automatically.
|
||||
*/
|
||||
int tab_interval;
|
||||
|
||||
/**
|
||||
* Array of all tabs set. Each entry is the column number of a tab + 1,
|
||||
* or 0 if that tab cell is unset.
|
||||
*/
|
||||
int custom_tabs[GUAC_TERMINAL_MAX_TABS];
|
||||
|
||||
/**
|
||||
* Array of arrays of mapped characters, where the character N is located at the N-32
|
||||
* position within the array. Each element in a contained array is the corresponding Unicode
|
||||
* codepoint. If NULL, a direct mapping from Unicode is used. The entries of the main array
|
||||
* correspond to the character set in use (G0, G1, etc.)
|
||||
*/
|
||||
const int* char_mapping[2];
|
||||
|
||||
/**
|
||||
* The active character set. For example, 0 for G0, 1 for G1, etc.
|
||||
*/
|
||||
int active_char_set;
|
||||
|
||||
/**
|
||||
* Whether text is being selected.
|
||||
*/
|
||||
bool text_selected;
|
||||
|
||||
/**
|
||||
* The row that the selection starts at.
|
||||
*/
|
||||
int selection_start_row;
|
||||
|
||||
/**
|
||||
* The column that the selection starts at.
|
||||
*/
|
||||
int selection_start_column;
|
||||
|
||||
/**
|
||||
* The row that the selection ends at.
|
||||
*/
|
||||
int selection_end_row;
|
||||
|
||||
/**
|
||||
* The column that the selection ends at.
|
||||
*/
|
||||
int selection_end_column;
|
||||
|
||||
/**
|
||||
* Whether the cursor (arrow) keys should send cursor sequences
|
||||
* or application sequences (DECCKM).
|
||||
*/
|
||||
bool application_cursor_keys;
|
||||
|
||||
/**
|
||||
* Whether a CR should automatically follow a LF, VT, or FF.
|
||||
*/
|
||||
bool automatic_carriage_return;
|
||||
|
||||
/**
|
||||
* Whether insert mode is enabled (DECIM).
|
||||
*/
|
||||
bool insert_mode;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new guac_terminal, having the given width and height, and
|
||||
* rendering to the given client.
|
||||
*/
|
||||
guac_terminal* guac_terminal_create(guac_client* client,
|
||||
const char* font_name, int font_size,
|
||||
int width, int height);
|
||||
|
||||
/**
|
||||
* Resets the state of the given terminal, as if it were just allocated.
|
||||
*/
|
||||
void guac_terminal_reset(guac_terminal* term);
|
||||
|
||||
/**
|
||||
* Frees all resources associated with the given terminal.
|
||||
*/
|
||||
void guac_terminal_free(guac_terminal* term);
|
||||
|
||||
/**
|
||||
* Writes the given string of characters to the terminal.
|
||||
*/
|
||||
int guac_terminal_write(guac_terminal* term, const char* c, int size);
|
||||
|
||||
/**
|
||||
* Sets the character at the given row and column to the specified value.
|
||||
*/
|
||||
int guac_terminal_set(guac_terminal* term, int row, int col, int codepoint);
|
||||
|
||||
/**
|
||||
* Clears the given region within a single row.
|
||||
*/
|
||||
int guac_terminal_clear_columns(guac_terminal* term,
|
||||
int row, int start_col, int end_col);
|
||||
|
||||
/**
|
||||
* Clears the given region from right-to-left, top-to-bottom, replacing
|
||||
* all characters with the current background color and attributes.
|
||||
*/
|
||||
int guac_terminal_clear_range(guac_terminal* term,
|
||||
int start_row, int start_col,
|
||||
int end_row, int end_col);
|
||||
|
||||
/**
|
||||
* Scrolls the terminal's current scroll region up by one row.
|
||||
*/
|
||||
int guac_terminal_scroll_up(guac_terminal* term,
|
||||
int start_row, int end_row, int amount);
|
||||
|
||||
/**
|
||||
* Scrolls the terminal's current scroll region down by one row.
|
||||
*/
|
||||
int guac_terminal_scroll_down(guac_terminal* term,
|
||||
int start_row, int end_row, int amount);
|
||||
|
||||
/**
|
||||
* Commits the current cursor location, updating the visible cursor
|
||||
* on the screen.
|
||||
*/
|
||||
void guac_terminal_commit_cursor(guac_terminal* term);
|
||||
|
||||
/**
|
||||
* Scroll down the display by the given amount, replacing the new space with
|
||||
* data from the buffer. If not enough data is available, the maximum
|
||||
* amount will be scrolled.
|
||||
*/
|
||||
void guac_terminal_scroll_display_down(guac_terminal* terminal, int amount);
|
||||
|
||||
/**
|
||||
* Scroll up the display by the given amount, replacing the new space with data
|
||||
* from either the buffer or the terminal buffer. If not enough data is
|
||||
* available, the maximum amount will be scrolled.
|
||||
*/
|
||||
void guac_terminal_scroll_display_up(guac_terminal* terminal, int amount);
|
||||
|
||||
/**
|
||||
* Marks the start of text selection at the given row and column.
|
||||
*/
|
||||
void guac_terminal_select_start(guac_terminal* terminal, int row, int column);
|
||||
|
||||
/**
|
||||
* Updates the end of text selection at the given row and column.
|
||||
*/
|
||||
void guac_terminal_select_update(guac_terminal* terminal, int row, int column);
|
||||
|
||||
/**
|
||||
* Ends text selection, removing any highlight. Character data is stored in the
|
||||
* string buffer provided.
|
||||
*/
|
||||
void guac_terminal_select_end(guac_terminal* terminal, char* string);
|
||||
|
||||
/* LOW-LEVEL TERMINAL OPERATIONS */
|
||||
|
||||
/**
|
||||
* Copies the given range of columns to a new location, offset from
|
||||
* the original by the given number of columns.
|
||||
*/
|
||||
void guac_terminal_copy_columns(guac_terminal* terminal, int row,
|
||||
int start_column, int end_column, int offset);
|
||||
|
||||
/**
|
||||
* Copies the given range of rows to a new location, offset from the
|
||||
* original by the given number of rows.
|
||||
*/
|
||||
void guac_terminal_copy_rows(guac_terminal* terminal,
|
||||
int start_row, int end_row, int offset);
|
||||
|
||||
/**
|
||||
* Sets the given range of columns within the given row to the given
|
||||
* character.
|
||||
*/
|
||||
void guac_terminal_set_columns(guac_terminal* terminal, int row,
|
||||
int start_column, int end_column, guac_terminal_char* character);
|
||||
|
||||
/**
|
||||
* Resize the terminal to the given dimensions.
|
||||
*/
|
||||
void guac_terminal_resize(guac_terminal* term, int width, int height);
|
||||
|
||||
/**
|
||||
* Flushes all pending operations within the given guac_terminal.
|
||||
*/
|
||||
void guac_terminal_flush(guac_terminal* terminal);
|
||||
|
||||
/**
|
||||
* Sends the given string as if typed by the user.
|
||||
*/
|
||||
int guac_terminal_send_data(guac_terminal* term, const char* data, int length);
|
||||
|
||||
/**
|
||||
* Sends the given string as if typed by the user.
|
||||
*/
|
||||
int guac_terminal_send_string(guac_terminal* term, const char* data);
|
||||
|
||||
/**
|
||||
* Sends data through STDIN as if typed by the user, using the format
|
||||
* string given and any args (similar to printf).
|
||||
*/
|
||||
int guac_terminal_sendf(guac_terminal* term, const char* format, ...);
|
||||
|
||||
/**
|
||||
* Sets a tabstop in the given column.
|
||||
*/
|
||||
void guac_terminal_set_tab(guac_terminal* term, int column);
|
||||
|
||||
/**
|
||||
* Removes the tabstop at the given column.
|
||||
*/
|
||||
void guac_terminal_unset_tab(guac_terminal* term, int column);
|
||||
|
||||
/**
|
||||
* Removes all tabstops.
|
||||
*/
|
||||
void guac_terminal_clear_tabs(guac_terminal* term);
|
||||
|
||||
/**
|
||||
* Given a column within the given terminal, returns the location of the
|
||||
* next tabstop (or the rightmost character, if no more tabstops exist).
|
||||
*/
|
||||
int guac_terminal_next_tab(guac_terminal* term, int column);
|
||||
|
||||
#endif
|
||||
|
54
protocols/ssh/include/terminal_handlers.h
Normal file
54
protocols/ssh/include/terminal_handlers.h
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_TERMINAL_HANDLERS
|
||||
#define _SSH_GUAC_TERMINAL_HANDLERS
|
||||
|
||||
#include "terminal.h"
|
||||
|
||||
int guac_terminal_echo(guac_terminal* term, char c);
|
||||
int guac_terminal_escape(guac_terminal* term, char c);
|
||||
int guac_terminal_g0_charset(guac_terminal* term, char c);
|
||||
int guac_terminal_g1_charset(guac_terminal* term, char c);
|
||||
int guac_terminal_g2_charset(guac_terminal* term, char c);
|
||||
int guac_terminal_g3_charset(guac_terminal* term, char c);
|
||||
int guac_terminal_csi(guac_terminal* term, char c);
|
||||
int guac_terminal_osc(guac_terminal* term, char c);
|
||||
int guac_terminal_ctrl_func(guac_terminal* term, char c);
|
||||
|
||||
#endif
|
||||
|
122
protocols/ssh/include/types.h
Normal file
122
protocols/ssh/include/types.h
Normal file
@ -0,0 +1,122 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _SSH_GUAC_TYPES_H
|
||||
#define _SSH_GUAC_TYPES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* An RGB color, where each component ranges from 0 to 255.
|
||||
*/
|
||||
typedef struct guac_terminal_color {
|
||||
|
||||
/**
|
||||
* The red component of this color.
|
||||
*/
|
||||
int red;
|
||||
|
||||
/**
|
||||
* The green component of this color.
|
||||
*/
|
||||
int green;
|
||||
|
||||
/**
|
||||
* The blue component of this color.
|
||||
*/
|
||||
int blue;
|
||||
|
||||
} guac_terminal_color;
|
||||
|
||||
/**
|
||||
* Terminal attributes, as can be applied to a single character.
|
||||
*/
|
||||
typedef struct guac_terminal_attributes {
|
||||
|
||||
/**
|
||||
* Whether the character should be rendered bold.
|
||||
*/
|
||||
bool bold;
|
||||
|
||||
/**
|
||||
* Whether the character should be rendered with reversed colors
|
||||
* (background becomes foreground and vice-versa).
|
||||
*/
|
||||
bool reverse;
|
||||
|
||||
/**
|
||||
* Whether the associated character is highlighted by the cursor.
|
||||
*/
|
||||
bool cursor;
|
||||
|
||||
/**
|
||||
* Whether to render the character with underscore.
|
||||
*/
|
||||
bool underscore;
|
||||
|
||||
/**
|
||||
* The foreground color of this character, as a palette index.
|
||||
*/
|
||||
int foreground;
|
||||
|
||||
/**
|
||||
* The background color of this character, as a palette index.
|
||||
*/
|
||||
int background;
|
||||
|
||||
} guac_terminal_attributes;
|
||||
|
||||
/**
|
||||
* Represents a single character for display in a terminal, including actual
|
||||
* character value, foreground color, and background color.
|
||||
*/
|
||||
typedef struct guac_terminal_char {
|
||||
|
||||
/**
|
||||
* The Unicode codepoint of the character to display.
|
||||
*/
|
||||
int value;
|
||||
|
||||
/**
|
||||
* The attributes of the character to display.
|
||||
*/
|
||||
guac_terminal_attributes attributes;
|
||||
|
||||
} guac_terminal_char;
|
||||
|
||||
#endif
|
||||
|
12
protocols/ssh/m4/README
Normal file
12
protocols/ssh/m4/README
Normal file
@ -0,0 +1,12 @@
|
||||
This file exists such that the m4/ directory will be created when cloning the
|
||||
git repository.
|
||||
|
||||
The m4/ directory is not directly used by this project, but libtoolize
|
||||
populates this directory with files, recommending that the directory be
|
||||
included in the macro search path for aclocal.
|
||||
|
||||
Because autoreconf runs aclocal before libtoolize, this directory will not
|
||||
exist when autoreconf is run, triggering an error from aclocal.
|
||||
|
||||
Creating this directory (and keeping this file in it as a placeholder)
|
||||
prevents this error.
|
64
protocols/ssh/src/blank.c
Normal file
64
protocols/ssh/src/blank.c
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
#include "cursor.h"
|
||||
|
||||
guac_ssh_cursor* guac_ssh_create_blank(guac_client* client) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
guac_ssh_cursor* cursor = guac_ssh_cursor_alloc(client);
|
||||
|
||||
/* Set buffer to a single 1x1 transparent rectangle */
|
||||
guac_protocol_send_rect(socket, cursor->buffer, 0, 0, 1, 1);
|
||||
guac_protocol_send_cfill(socket, GUAC_COMP_SRC, cursor->buffer,
|
||||
0x00, 0x00, 0x00, 0x00);
|
||||
|
||||
/* Initialize cursor properties */
|
||||
cursor->width = 1;
|
||||
cursor->height = 1;
|
||||
cursor->hotspot_x = 0;
|
||||
cursor->hotspot_y = 0;
|
||||
|
||||
return cursor;
|
||||
|
||||
}
|
||||
|
214
protocols/ssh/src/buffer.c
Normal file
214
protocols/ssh/src/buffer.c
Normal file
@ -0,0 +1,214 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "common.h"
|
||||
|
||||
guac_terminal_buffer* guac_terminal_buffer_alloc(int rows, guac_terminal_char* default_character) {
|
||||
|
||||
/* Allocate scrollback */
|
||||
guac_terminal_buffer* buffer =
|
||||
malloc(sizeof(guac_terminal_buffer));
|
||||
|
||||
int i;
|
||||
guac_terminal_buffer_row* row;
|
||||
|
||||
/* Init scrollback data */
|
||||
buffer->default_character = *default_character;
|
||||
buffer->available = rows;
|
||||
buffer->top = 0;
|
||||
buffer->length = 0;
|
||||
buffer->rows = malloc(sizeof(guac_terminal_buffer_row) *
|
||||
buffer->available);
|
||||
|
||||
/* Init scrollback rows */
|
||||
row = buffer->rows;
|
||||
for (i=0; i<rows; i++) {
|
||||
|
||||
/* Allocate row */
|
||||
row->available = 256;
|
||||
row->length = 0;
|
||||
row->characters = malloc(sizeof(guac_terminal_char) * row->available);
|
||||
|
||||
/* Next row */
|
||||
row++;
|
||||
|
||||
}
|
||||
|
||||
return buffer;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_buffer_free(guac_terminal_buffer* buffer) {
|
||||
|
||||
int i;
|
||||
guac_terminal_buffer_row* row = buffer->rows;
|
||||
|
||||
/* Free all rows */
|
||||
for (i=0; i<buffer->available; i++) {
|
||||
free(row->characters);
|
||||
row++;
|
||||
}
|
||||
|
||||
/* Free actual buffer */
|
||||
free(buffer->rows);
|
||||
free(buffer);
|
||||
|
||||
}
|
||||
|
||||
guac_terminal_buffer_row* guac_terminal_buffer_get_row(guac_terminal_buffer* buffer, int row, int width) {
|
||||
|
||||
int i;
|
||||
guac_terminal_char* first;
|
||||
guac_terminal_buffer_row* buffer_row;
|
||||
|
||||
/* Calculate scrollback row index */
|
||||
int index = buffer->top + row;
|
||||
if (index < 0)
|
||||
index += buffer->available;
|
||||
else if (index >= buffer->available)
|
||||
index -= buffer->available;
|
||||
|
||||
/* Get row */
|
||||
buffer_row = &(buffer->rows[index]);
|
||||
|
||||
/* If resizing is needed */
|
||||
if (width >= buffer_row->length) {
|
||||
|
||||
/* Expand if necessary */
|
||||
if (width > buffer_row->available) {
|
||||
buffer_row->available = width*2;
|
||||
buffer_row->characters = realloc(buffer_row->characters, sizeof(guac_terminal_char) * buffer_row->available);
|
||||
}
|
||||
|
||||
/* Initialize new part of row */
|
||||
first = &(buffer_row->characters[buffer_row->length]);
|
||||
for (i=buffer_row->length; i<width; i++)
|
||||
*(first++) = buffer->default_character;
|
||||
|
||||
buffer_row->length = width;
|
||||
|
||||
}
|
||||
|
||||
/* Return found row */
|
||||
return buffer_row;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_buffer_copy_columns(guac_terminal_buffer* buffer, int row,
|
||||
int start_column, int end_column, int offset) {
|
||||
|
||||
guac_terminal_char* src;
|
||||
guac_terminal_char* dst;
|
||||
|
||||
/* Get row */
|
||||
guac_terminal_buffer_row* buffer_row = guac_terminal_buffer_get_row(buffer, row, end_column + offset + 1);
|
||||
|
||||
/* Fit range within bounds */
|
||||
start_column = guac_terminal_fit_to_range(start_column, 0, buffer_row->length - 1);
|
||||
end_column = guac_terminal_fit_to_range(end_column, 0, buffer_row->length - 1);
|
||||
start_column = guac_terminal_fit_to_range(start_column + offset, 0, buffer_row->length - 1) - offset;
|
||||
end_column = guac_terminal_fit_to_range(end_column + offset, 0, buffer_row->length - 1) - offset;
|
||||
|
||||
/* Determine source and destination locations */
|
||||
src = &(buffer_row->characters[start_column]);
|
||||
dst = &(buffer_row->characters[start_column + offset]);
|
||||
|
||||
/* Copy data */
|
||||
memmove(dst, src, sizeof(guac_terminal_char) * (end_column - start_column + 1));
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_buffer_copy_rows(guac_terminal_buffer* buffer,
|
||||
int start_row, int end_row, int offset) {
|
||||
|
||||
int i, current_row;
|
||||
int step;
|
||||
|
||||
/* If shifting down, copy in reverse */
|
||||
if (offset > 0) {
|
||||
current_row = end_row;
|
||||
step = -1;
|
||||
}
|
||||
|
||||
/* Otherwise, copy forwards */
|
||||
else {
|
||||
current_row = start_row;
|
||||
step = 1;
|
||||
}
|
||||
|
||||
/* Copy each current_row individually */
|
||||
for (i = start_row; i <= end_row; i++) {
|
||||
|
||||
/* Get source and destination rows */
|
||||
guac_terminal_buffer_row* src_row = guac_terminal_buffer_get_row(buffer, current_row, 0);
|
||||
guac_terminal_buffer_row* dst_row = guac_terminal_buffer_get_row(buffer, current_row + offset, src_row->length);
|
||||
|
||||
/* Copy data */
|
||||
memcpy(dst_row->characters, src_row->characters, sizeof(guac_terminal_char) * src_row->length);
|
||||
dst_row->length = src_row->length;
|
||||
|
||||
/* Next current_row */
|
||||
current_row += step;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_buffer_set_columns(guac_terminal_buffer* buffer, int row,
|
||||
int start_column, int end_column, guac_terminal_char* character) {
|
||||
|
||||
int i;
|
||||
guac_terminal_char* current;
|
||||
|
||||
/* Get and expand row */
|
||||
guac_terminal_buffer_row* buffer_row = guac_terminal_buffer_get_row(buffer, row, end_column+1);
|
||||
|
||||
/* Set values */
|
||||
current = &(buffer_row->characters[start_column]);
|
||||
for (i=start_column; i<=end_column; i++)
|
||||
*(current++) = *character;
|
||||
|
||||
/* Update length depending on row written */
|
||||
if (row >= buffer->length)
|
||||
buffer->length = row+1;
|
||||
|
||||
}
|
||||
|
88
protocols/ssh/src/char_mappings.c
Normal file
88
protocols/ssh/src/char_mappings.c
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const int vt100_map[] = {
|
||||
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
||||
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
|
||||
0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x00B0, 0x00B1, 0x2424, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA,
|
||||
0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252C, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00B7, 0x007F,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
|
||||
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
|
||||
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
|
||||
};
|
||||
|
||||
const int null_map[] = {
|
||||
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
||||
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
|
||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x007F,
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x000A
|
||||
};
|
||||
|
||||
const int user_map[] = {
|
||||
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
||||
0x00A7, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00C4, 0x00D6, 0x00DC, '^', '_',
|
||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0x00E4, 0x00F6, 0x00FC, 0x00DF, 0x007F,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
|
||||
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
|
||||
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
|
||||
};
|
||||
|
186
protocols/ssh/src/client.c
Normal file
186
protocols/ssh/src/client.c
Normal file
@ -0,0 +1,186 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Muehlner <dagger10k@users.sourceforge.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/error.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "guac_handlers.h"
|
||||
#include "terminal.h"
|
||||
#include "blank.h"
|
||||
#include "ibar.h"
|
||||
#include "ssh_client.h"
|
||||
|
||||
#define GUAC_SSH_DEFAULT_FONT_NAME "monospace"
|
||||
#define GUAC_SSH_DEFAULT_FONT_SIZE 12
|
||||
#define GUAC_SSH_DEFAULT_PORT 22
|
||||
|
||||
/* Client plugin arguments */
|
||||
const char* GUAC_CLIENT_ARGS[] = {
|
||||
"hostname",
|
||||
"port",
|
||||
"username",
|
||||
"password",
|
||||
"font-name",
|
||||
"font-size",
|
||||
NULL
|
||||
};
|
||||
|
||||
enum __SSH_ARGS_IDX {
|
||||
|
||||
/**
|
||||
* The hostname to connect to. Required.
|
||||
*/
|
||||
IDX_HOSTNAME,
|
||||
|
||||
/**
|
||||
* The port to connect to. Optional.
|
||||
*/
|
||||
IDX_PORT,
|
||||
|
||||
/**
|
||||
* The name of the user to login as. Optional.
|
||||
*/
|
||||
IDX_USERNAME,
|
||||
|
||||
/**
|
||||
* The password to use when logging in. Optional.
|
||||
*/
|
||||
IDX_PASSWORD,
|
||||
|
||||
/**
|
||||
* The name of the font to use within the terminal.
|
||||
*/
|
||||
IDX_FONT_NAME,
|
||||
|
||||
/**
|
||||
* The size of the font to use within the terminal, in points.
|
||||
*/
|
||||
IDX_FONT_SIZE,
|
||||
|
||||
SSH_ARGS_COUNT
|
||||
};
|
||||
|
||||
int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
|
||||
ssh_guac_client_data* client_data = malloc(sizeof(ssh_guac_client_data));
|
||||
|
||||
/* Init client data */
|
||||
client->data = client_data;
|
||||
client_data->mod_alt =
|
||||
client_data->mod_ctrl =
|
||||
client_data->mod_shift = 0;
|
||||
client_data->clipboard_data = NULL;
|
||||
client_data->term_channel = NULL;
|
||||
|
||||
if (argc != SSH_ARGS_COUNT) {
|
||||
guac_client_log_error(client, "Wrong number of arguments");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read parameters */
|
||||
strcpy(client_data->hostname, argv[IDX_HOSTNAME]);
|
||||
strcpy(client_data->username, argv[IDX_USERNAME]);
|
||||
strcpy(client_data->password, argv[IDX_PASSWORD]);
|
||||
|
||||
/* Read font name */
|
||||
if (argv[IDX_FONT_NAME][0] != 0)
|
||||
strcpy(client_data->font_name, argv[IDX_FONT_NAME]);
|
||||
else
|
||||
strcpy(client_data->font_name, GUAC_SSH_DEFAULT_FONT_NAME );
|
||||
|
||||
/* Read font size */
|
||||
if (argv[IDX_FONT_SIZE][0] != 0)
|
||||
client_data->font_size = atoi(argv[IDX_FONT_SIZE]);
|
||||
else
|
||||
client_data->font_size = GUAC_SSH_DEFAULT_FONT_SIZE;
|
||||
|
||||
/* Read port */
|
||||
if (argv[IDX_PORT][0] != 0)
|
||||
client_data->port = atoi(argv[IDX_PORT]);
|
||||
else
|
||||
client_data->port = GUAC_SSH_DEFAULT_PORT;
|
||||
|
||||
/* Create terminal */
|
||||
client_data->term = guac_terminal_create(client,
|
||||
client_data->font_name, client_data->font_size,
|
||||
client->info.optimal_width, client->info.optimal_height);
|
||||
|
||||
/* Set up I-bar pointer */
|
||||
client_data->ibar_cursor = guac_ssh_create_ibar(client);
|
||||
|
||||
/* Set up blank pointer */
|
||||
client_data->blank_cursor = guac_ssh_create_blank(client);
|
||||
|
||||
/* Send initial name */
|
||||
guac_protocol_send_name(socket, client_data->hostname);
|
||||
|
||||
/* Initialize pointer */
|
||||
client_data->current_cursor = client_data->blank_cursor;
|
||||
guac_ssh_set_cursor(client, client_data->current_cursor);
|
||||
|
||||
guac_socket_flush(socket);
|
||||
|
||||
/* Set basic handlers */
|
||||
client->handle_messages = ssh_guac_client_handle_messages;
|
||||
client->clipboard_handler = ssh_guac_client_clipboard_handler;
|
||||
client->key_handler = ssh_guac_client_key_handler;
|
||||
client->mouse_handler = ssh_guac_client_mouse_handler;
|
||||
client->size_handler = ssh_guac_client_size_handler;
|
||||
client->free_handler = ssh_guac_client_free_handler;
|
||||
|
||||
/* Start client thread */
|
||||
if (pthread_create(&(client_data->client_thread), NULL, ssh_client_thread, (void*) client)) {
|
||||
guac_client_log_error(client, "Unable to SSH client thread");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
121
protocols/ssh/src/common.c
Normal file
121
protocols/ssh/src/common.c
Normal file
@ -0,0 +1,121 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int guac_terminal_fit_to_range(int value, int min, int max) {
|
||||
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_encode_utf8(int codepoint, char* utf8) {
|
||||
|
||||
int i;
|
||||
int mask, bytes;
|
||||
|
||||
/* Determine size and initial byte mask */
|
||||
if (codepoint <= 0x007F) {
|
||||
mask = 0x00;
|
||||
bytes = 1;
|
||||
}
|
||||
else if (codepoint <= 0x7FF) {
|
||||
mask = 0xC0;
|
||||
bytes = 2;
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
mask = 0xE0;
|
||||
bytes = 3;
|
||||
}
|
||||
else if (codepoint <= 0x1FFFFF) {
|
||||
mask = 0xF0;
|
||||
bytes = 4;
|
||||
}
|
||||
|
||||
/* Otherwise, invalid codepoint */
|
||||
else {
|
||||
*(utf8++) = '?';
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Offset buffer by size */
|
||||
utf8 += bytes - 1;
|
||||
|
||||
/* Add trailing bytes, if any */
|
||||
for (i=1; i<bytes; i++) {
|
||||
*(utf8--) = 0x80 | (codepoint & 0x3F);
|
||||
codepoint >>= 6;
|
||||
}
|
||||
|
||||
/* Set initial byte */
|
||||
*utf8 = mask | codepoint;
|
||||
|
||||
/* Done */
|
||||
return bytes;
|
||||
|
||||
}
|
||||
|
||||
bool guac_terminal_has_glyph(int codepoint) {
|
||||
return
|
||||
codepoint != 0
|
||||
&& codepoint != ' ';
|
||||
}
|
||||
|
||||
int guac_terminal_write_all(int fd, const char* buffer, int size) {
|
||||
|
||||
int remaining = size;
|
||||
while (remaining > 0) {
|
||||
|
||||
/* Attempt to write data */
|
||||
int ret_val = write(fd, buffer, remaining);
|
||||
if (ret_val <= 0)
|
||||
return -1;
|
||||
|
||||
/* If successful, contine with what data remains (if any) */
|
||||
remaining -= ret_val;
|
||||
buffer += ret_val;
|
||||
|
||||
}
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
|
74
protocols/ssh/src/cursor.c
Normal file
74
protocols/ssh/src/cursor.c
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
|
||||
#include "cursor.h"
|
||||
|
||||
guac_ssh_cursor* guac_ssh_cursor_alloc(guac_client* client) {
|
||||
|
||||
/* Alloc new cursor, initialize buffer */
|
||||
guac_ssh_cursor* cursor = malloc(sizeof(guac_ssh_cursor));
|
||||
cursor->buffer = guac_client_alloc_buffer(client);
|
||||
|
||||
return cursor;
|
||||
|
||||
}
|
||||
|
||||
void guac_ssh_cursor_free(guac_client* client, guac_ssh_cursor* cursor) {
|
||||
|
||||
/* Free buffer */
|
||||
guac_client_free_buffer(client, cursor->buffer);
|
||||
|
||||
/* Free cursor */
|
||||
free(cursor);
|
||||
|
||||
}
|
||||
|
||||
void guac_ssh_set_cursor(guac_client* client, guac_ssh_cursor* cursor) {
|
||||
|
||||
/* Set cursor */
|
||||
guac_protocol_send_cursor(client->socket,
|
||||
cursor->hotspot_x, cursor->hotspot_y,
|
||||
cursor->buffer,
|
||||
0, 0, cursor->width, cursor->height);
|
||||
|
||||
}
|
||||
|
1010
protocols/ssh/src/display.c
Normal file
1010
protocols/ssh/src/display.c
Normal file
File diff suppressed because it is too large
Load Diff
445
protocols/ssh/src/guac_handlers.c
Normal file
445
protocols/ssh/src/guac_handlers.c
Normal file
@ -0,0 +1,445 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Muehlner <dagger10k@users.sourceforge.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/error.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include "libssh_compat.h"
|
||||
|
||||
#include "guac_handlers.h"
|
||||
#include "client.h"
|
||||
#include "common.h"
|
||||
#include "cursor.h"
|
||||
|
||||
int ssh_guac_client_handle_messages(guac_client* client) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
char buffer[8192];
|
||||
|
||||
int ret_val;
|
||||
int fd = client_data->term->stdout_pipe_fd[0];
|
||||
struct timeval timeout;
|
||||
fd_set fds;
|
||||
|
||||
/* Build fd_set */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
/* Time to wait */
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* Wait for data to be available */
|
||||
ret_val = select(fd+1, &fds, NULL, NULL, &timeout);
|
||||
if (ret_val > 0) {
|
||||
|
||||
int bytes_read = 0;
|
||||
|
||||
/* Lock terminal access */
|
||||
pthread_mutex_lock(&(client_data->term->lock));
|
||||
|
||||
/* Read data, write to terminal */
|
||||
if ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
|
||||
if (guac_terminal_write(client_data->term, buffer, bytes_read))
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Notify on error */
|
||||
if (bytes_read < 0) {
|
||||
guac_protocol_send_error(socket, "Error reading data.");
|
||||
guac_socket_flush(socket);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Update cursor */
|
||||
guac_terminal_commit_cursor(client_data->term);
|
||||
|
||||
/* Flush terminal display */
|
||||
guac_terminal_display_flush(client_data->term->display);
|
||||
|
||||
/* Unlock terminal access */
|
||||
pthread_mutex_unlock(&(client_data->term->lock));
|
||||
|
||||
}
|
||||
else if (ret_val < 0) {
|
||||
guac_error_message = "Error waiting for pipe";
|
||||
guac_error = GUAC_STATUS_SEE_ERRNO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int ssh_guac_client_clipboard_handler(guac_client* client, char* data) {
|
||||
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
|
||||
free(client_data->clipboard_data);
|
||||
|
||||
client_data->clipboard_data = strdup(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ssh_guac_client_mouse_handler(guac_client* client, int x, int y, int mask) {
|
||||
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
guac_terminal* term = client_data->term;
|
||||
|
||||
/* Determine which buttons were just released and pressed */
|
||||
int released_mask = client_data->mouse_mask & ~mask;
|
||||
int pressed_mask = ~client_data->mouse_mask & mask;
|
||||
|
||||
client_data->mouse_mask = mask;
|
||||
|
||||
/* Show mouse cursor if not already shown */
|
||||
if (client_data->current_cursor != client_data->ibar_cursor) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
|
||||
client_data->current_cursor = client_data->ibar_cursor;
|
||||
guac_ssh_set_cursor(client, client_data->ibar_cursor);
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
}
|
||||
|
||||
/* Paste contents of clipboard on right or middle mouse button up */
|
||||
if ((released_mask & GUAC_CLIENT_MOUSE_RIGHT) || (released_mask & GUAC_CLIENT_MOUSE_MIDDLE)) {
|
||||
if (client_data->clipboard_data != NULL)
|
||||
return guac_terminal_send_string(term, client_data->clipboard_data);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If text selected, change state based on left mouse mouse button */
|
||||
if (term->text_selected) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
|
||||
/* If mouse button released, stop selection */
|
||||
if (released_mask & GUAC_CLIENT_MOUSE_LEFT) {
|
||||
|
||||
/* End selection and get selected text */
|
||||
char* string = malloc(term->term_width * term->term_height * sizeof(char));
|
||||
guac_terminal_select_end(term, string);
|
||||
|
||||
/* Store new data */
|
||||
free(client_data->clipboard_data);
|
||||
client_data->clipboard_data = string;
|
||||
|
||||
/* Send data */
|
||||
guac_protocol_send_clipboard(client->socket, string);
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, just update */
|
||||
else
|
||||
guac_terminal_select_update(term,
|
||||
y / term->display->char_height - term->scroll_offset,
|
||||
x / term->display->char_width);
|
||||
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
}
|
||||
|
||||
/* Otherwise, if mouse button pressed AND moved, start selection */
|
||||
else if (!(pressed_mask & GUAC_CLIENT_MOUSE_LEFT) &&
|
||||
mask & GUAC_CLIENT_MOUSE_LEFT) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
|
||||
guac_terminal_select_start(term,
|
||||
y / term->display->char_height - term->scroll_offset,
|
||||
x / term->display->char_width);
|
||||
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
}
|
||||
|
||||
/* Scroll up if wheel moved up */
|
||||
if (released_mask & GUAC_CLIENT_MOUSE_SCROLL_UP) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
guac_terminal_scroll_display_up(term, GUAC_SSH_WHEEL_SCROLL_AMOUNT);
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
}
|
||||
|
||||
/* Scroll down if wheel moved down */
|
||||
if (released_mask & GUAC_CLIENT_MOUSE_SCROLL_DOWN) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
guac_terminal_scroll_display_down(term, GUAC_SSH_WHEEL_SCROLL_AMOUNT);
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
||||
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
guac_terminal* term = client_data->term;
|
||||
|
||||
/* Hide mouse cursor if not already hidden */
|
||||
if (client_data->current_cursor != client_data->blank_cursor) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
|
||||
client_data->current_cursor = client_data->blank_cursor;
|
||||
guac_ssh_set_cursor(client, client_data->blank_cursor);
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
}
|
||||
|
||||
/* Track modifiers */
|
||||
if (keysym == 0xFFE3)
|
||||
client_data->mod_ctrl = pressed;
|
||||
else if (keysym == 0xFFE9)
|
||||
client_data->mod_alt = pressed;
|
||||
else if (keysym == 0xFFE1)
|
||||
client_data->mod_shift = pressed;
|
||||
|
||||
/* If key pressed */
|
||||
else if (pressed) {
|
||||
|
||||
/* Ctrl+Shift+V shortcut for paste */
|
||||
if (keysym == 'V' && client_data->mod_ctrl) {
|
||||
if (client_data->clipboard_data != NULL)
|
||||
return guac_terminal_send_string(term, client_data->clipboard_data);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Shift+PgUp / Shift+PgDown shortcuts for scrolling */
|
||||
if (client_data->mod_shift) {
|
||||
|
||||
/* Page up */
|
||||
if (keysym == 0xFF55) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
guac_terminal_scroll_display_up(term, term->term_height);
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Page down */
|
||||
if (keysym == 0xFF56) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
guac_terminal_scroll_display_down(term, term->term_height);
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Reset scroll */
|
||||
if (term->scroll_offset != 0) {
|
||||
pthread_mutex_lock(&(term->lock));
|
||||
guac_terminal_scroll_display_down(term, term->scroll_offset);
|
||||
pthread_mutex_unlock(&(term->lock));
|
||||
}
|
||||
|
||||
/* If alt being held, also send escape character */
|
||||
if (client_data->mod_alt)
|
||||
return guac_terminal_send_string(term, "\x1B");
|
||||
|
||||
/* Translate Ctrl+letter to control code */
|
||||
if (client_data->mod_ctrl) {
|
||||
|
||||
char data;
|
||||
|
||||
/* If valid control code, send it */
|
||||
if (keysym >= 'A' && keysym <= 'Z')
|
||||
data = (char) (keysym - 'A' + 1);
|
||||
else if (keysym >= 'a' && keysym <= 'z')
|
||||
data = (char) (keysym - 'a' + 1);
|
||||
|
||||
/* Otherwise ignore */
|
||||
else
|
||||
return 0;
|
||||
|
||||
return guac_terminal_send_data(term, &data, 1);
|
||||
|
||||
}
|
||||
|
||||
/* Translate Unicode to UTF-8 */
|
||||
else if ((keysym >= 0x00 && keysym <= 0xFF) || ((keysym & 0xFFFF0000) == 0x01000000)) {
|
||||
|
||||
int length;
|
||||
char data[5];
|
||||
|
||||
length = guac_terminal_encode_utf8(keysym & 0xFFFF, data);
|
||||
return guac_terminal_send_data(term, data, length);
|
||||
|
||||
}
|
||||
|
||||
/* Non-printable keys */
|
||||
else {
|
||||
|
||||
if (keysym == 0xFF08) return guac_terminal_send_string(term, "\x7F"); /* Backspace */
|
||||
if (keysym == 0xFF09) return guac_terminal_send_string(term, "\x09"); /* Tab */
|
||||
if (keysym == 0xFF0D) return guac_terminal_send_string(term, "\x0D"); /* Enter */
|
||||
if (keysym == 0xFF1B) return guac_terminal_send_string(term, "\x1B"); /* Esc */
|
||||
|
||||
if (keysym == 0xFF50) return guac_terminal_send_string(term, "\x1B[1~"); /* Home */
|
||||
|
||||
/* Arrow keys w/ application cursor */
|
||||
if (term->application_cursor_keys) {
|
||||
if (keysym == 0xFF51) return guac_terminal_send_string(term, "\x1BOD"); /* Left */
|
||||
if (keysym == 0xFF52) return guac_terminal_send_string(term, "\x1BOA"); /* Up */
|
||||
if (keysym == 0xFF53) return guac_terminal_send_string(term, "\x1BOC"); /* Right */
|
||||
if (keysym == 0xFF54) return guac_terminal_send_string(term, "\x1BOB"); /* Down */
|
||||
}
|
||||
else {
|
||||
if (keysym == 0xFF51) return guac_terminal_send_string(term, "\x1B[D"); /* Left */
|
||||
if (keysym == 0xFF52) return guac_terminal_send_string(term, "\x1B[A"); /* Up */
|
||||
if (keysym == 0xFF53) return guac_terminal_send_string(term, "\x1B[C"); /* Right */
|
||||
if (keysym == 0xFF54) return guac_terminal_send_string(term, "\x1B[B"); /* Down */
|
||||
}
|
||||
|
||||
if (keysym == 0xFF55) return guac_terminal_send_string(term, "\x1B[5~"); /* Page up */
|
||||
if (keysym == 0xFF56) return guac_terminal_send_string(term, "\x1B[6~"); /* Page down */
|
||||
if (keysym == 0xFF57) return guac_terminal_send_string(term, "\x1B[4~"); /* End */
|
||||
|
||||
if (keysym == 0xFF63) return guac_terminal_send_string(term, "\x1B[2~"); /* Insert */
|
||||
|
||||
if (keysym == 0xFFBE) return guac_terminal_send_string(term, "\x1B[[A"); /* F1 */
|
||||
if (keysym == 0xFFBF) return guac_terminal_send_string(term, "\x1B[[B"); /* F2 */
|
||||
if (keysym == 0xFFC0) return guac_terminal_send_string(term, "\x1B[[C"); /* F3 */
|
||||
if (keysym == 0xFFC1) return guac_terminal_send_string(term, "\x1B[[D"); /* F4 */
|
||||
if (keysym == 0xFFC2) return guac_terminal_send_string(term, "\x1B[[E"); /* F5 */
|
||||
|
||||
if (keysym == 0xFFC3) return guac_terminal_send_string(term, "\x1B[17~"); /* F6 */
|
||||
if (keysym == 0xFFC4) return guac_terminal_send_string(term, "\x1B[18~"); /* F7 */
|
||||
if (keysym == 0xFFC5) return guac_terminal_send_string(term, "\x1B[19~"); /* F8 */
|
||||
if (keysym == 0xFFC6) return guac_terminal_send_string(term, "\x1B[20~"); /* F9 */
|
||||
if (keysym == 0xFFC7) return guac_terminal_send_string(term, "\x1B[21~"); /* F10 */
|
||||
if (keysym == 0xFFC8) return guac_terminal_send_string(term, "\x1B[22~"); /* F11 */
|
||||
if (keysym == 0xFFC9) return guac_terminal_send_string(term, "\x1B[23~"); /* F12 */
|
||||
|
||||
if (keysym == 0xFFFF) return guac_terminal_send_string(term, "\x1B[3~"); /* Delete */
|
||||
|
||||
/* Ignore unknown keys */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int ssh_guac_client_size_handler(guac_client* client, int width, int height) {
|
||||
|
||||
/* Get terminal */
|
||||
ssh_guac_client_data* guac_client_data = (ssh_guac_client_data*) client->data;
|
||||
guac_terminal* terminal = guac_client_data->term;
|
||||
|
||||
/* Calculate dimensions */
|
||||
int rows = height / terminal->display->char_height;
|
||||
int columns = width / terminal->display->char_width;
|
||||
|
||||
pthread_mutex_lock(&(terminal->lock));
|
||||
|
||||
/* If size has changed */
|
||||
if (columns != terminal->term_width || rows != terminal->term_height) {
|
||||
|
||||
/* Resize terminal */
|
||||
guac_terminal_resize(terminal, columns, rows);
|
||||
|
||||
/* Update SSH pty size if connected */
|
||||
if (guac_client_data->term_channel != NULL)
|
||||
channel_change_pty_size(guac_client_data->term_channel,
|
||||
terminal->term_width, terminal->term_height);
|
||||
|
||||
/* Reset scroll region */
|
||||
terminal->scroll_end = rows - 1;
|
||||
|
||||
guac_terminal_display_flush(terminal->display);
|
||||
guac_socket_flush(terminal->client->socket);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&(terminal->lock));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssh_guac_client_free_handler(guac_client* client) {
|
||||
|
||||
ssh_guac_client_data* guac_client_data = (ssh_guac_client_data*) client->data;
|
||||
|
||||
/* Close SSH channel */
|
||||
if (guac_client_data->term_channel != NULL) {
|
||||
ssh_channel_close(guac_client_data->term_channel);
|
||||
ssh_channel_send_eof(guac_client_data->term_channel);
|
||||
}
|
||||
|
||||
/* Free terminal */
|
||||
guac_terminal_free(guac_client_data->term);
|
||||
pthread_join(guac_client_data->client_thread, NULL);
|
||||
|
||||
/* Free channels */
|
||||
ssh_channel_free(guac_client_data->term_channel);
|
||||
|
||||
/* Free session */
|
||||
ssh_free(guac_client_data->session);
|
||||
|
||||
/* Free clipboard data */
|
||||
free(guac_client_data->clipboard_data);
|
||||
|
||||
/* Free cursors */
|
||||
guac_ssh_cursor_free(client, guac_client_data->ibar_cursor);
|
||||
guac_ssh_cursor_free(client, guac_client_data->blank_cursor);
|
||||
|
||||
/* Free generic data struct */
|
||||
free(client->data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
108
protocols/ssh/src/ibar.c
Normal file
108
protocols/ssh/src/ibar.c
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
#include "cursor.h"
|
||||
|
||||
/* Macros for prettying up the embedded image. */
|
||||
#define X 0x00,0x00,0x00,0xFF
|
||||
#define U 0x80,0x80,0x80,0xFF
|
||||
#define O 0xFF,0xFF,0xFF,0xFF
|
||||
#define _ 0x00,0x00,0x00,0x00
|
||||
|
||||
/* Dimensions */
|
||||
const int guac_ssh_ibar_width = 7;
|
||||
const int guac_ssh_ibar_height = 16;
|
||||
|
||||
/* Format */
|
||||
const cairo_format_t guac_ssh_ibar_format = CAIRO_FORMAT_ARGB32;
|
||||
const int guac_ssh_ibar_stride = 28;
|
||||
|
||||
/* Embedded pointer graphic */
|
||||
unsigned char guac_ssh_ibar[] = {
|
||||
|
||||
X,X,X,X,X,X,X,
|
||||
X,O,O,U,O,O,X,
|
||||
X,X,X,O,X,X,X,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
_,_,X,O,X,_,_,
|
||||
X,X,X,O,X,X,X,
|
||||
X,O,O,U,O,O,X,
|
||||
X,X,X,X,X,X,X
|
||||
|
||||
};
|
||||
|
||||
|
||||
guac_ssh_cursor* guac_ssh_create_ibar(guac_client* client) {
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
guac_ssh_cursor* cursor = guac_ssh_cursor_alloc(client);
|
||||
|
||||
/* Draw to buffer */
|
||||
cairo_surface_t* graphic = cairo_image_surface_create_for_data(
|
||||
guac_ssh_ibar,
|
||||
guac_ssh_ibar_format,
|
||||
guac_ssh_ibar_width,
|
||||
guac_ssh_ibar_height,
|
||||
guac_ssh_ibar_stride);
|
||||
|
||||
guac_protocol_send_png(socket, GUAC_COMP_SRC, cursor->buffer,
|
||||
0, 0, graphic);
|
||||
cairo_surface_destroy(graphic);
|
||||
|
||||
/* Initialize cursor properties */
|
||||
cursor->width = guac_ssh_ibar_width;
|
||||
cursor->height = guac_ssh_ibar_height;
|
||||
cursor->hotspot_x = guac_ssh_ibar_width / 2;
|
||||
cursor->hotspot_y = guac_ssh_ibar_height / 2;
|
||||
|
||||
return cursor;
|
||||
|
||||
}
|
||||
|
252
protocols/ssh/src/ssh_client.c
Normal file
252
protocols/ssh/src/ssh_client.c
Normal file
@ -0,0 +1,252 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Muehlner <dagger10k@users.sourceforge.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* Reads a single line from STDIN.
|
||||
*/
|
||||
static char* prompt(guac_client* client, const char* title, char* str, int size, bool echo) {
|
||||
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
|
||||
int pos;
|
||||
char in_byte;
|
||||
|
||||
/* Get STDIN and STDOUT */
|
||||
int stdin_fd = client_data->term->stdin_pipe_fd[0];
|
||||
int stdout_fd = client_data->term->stdout_pipe_fd[1];
|
||||
|
||||
/* Print title */
|
||||
guac_terminal_write_all(stdout_fd, title, strlen(title));
|
||||
|
||||
/* Make room for null terminator */
|
||||
size--;
|
||||
|
||||
/* Read bytes until newline */
|
||||
pos = 0;
|
||||
while (pos < size && read(stdin_fd, &in_byte, 1) == 1) {
|
||||
|
||||
/* Backspace */
|
||||
if (in_byte == 0x7F) {
|
||||
|
||||
if (pos > 0) {
|
||||
guac_terminal_write_all(stdout_fd, "\b \b", 3);
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
|
||||
/* CR (end of input */
|
||||
else if (in_byte == 0x0D) {
|
||||
guac_terminal_write_all(stdout_fd, "\r\n", 2);
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
/* Store character, update buffers */
|
||||
str[pos++] = in_byte;
|
||||
|
||||
/* Print character if echoing */
|
||||
if (echo)
|
||||
guac_terminal_write_all(stdout_fd, &in_byte, 1);
|
||||
else
|
||||
guac_terminal_write_all(stdout_fd, "*", 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
str[pos] = 0;
|
||||
return str;
|
||||
|
||||
}
|
||||
|
||||
void* ssh_input_thread(void* data) {
|
||||
|
||||
guac_client* client = (guac_client*) data;
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
|
||||
char buffer[8192];
|
||||
int bytes_read;
|
||||
|
||||
int stdin_fd = client_data->term->stdin_pipe_fd[0];
|
||||
|
||||
/* Write all data read */
|
||||
while ((bytes_read = read(stdin_fd, buffer, sizeof(buffer))) > 0)
|
||||
channel_write(client_data->term_channel, buffer, bytes_read);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void* ssh_client_thread(void* data) {
|
||||
|
||||
guac_client* client = (guac_client*) data;
|
||||
ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
|
||||
|
||||
char name[1024];
|
||||
|
||||
guac_socket* socket = client->socket;
|
||||
char buffer[8192];
|
||||
int bytes_read = -1234;
|
||||
|
||||
int stdout_fd = client_data->term->stdout_pipe_fd[1];
|
||||
|
||||
pthread_t input_thread;
|
||||
|
||||
/* Get username */
|
||||
if (client_data->username[0] == 0 &&
|
||||
prompt(client, "Login as: ", client_data->username, sizeof(client_data->username), true) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Send new name */
|
||||
snprintf(name, sizeof(name)-1, "%s@%s", client_data->username, client_data->hostname);
|
||||
guac_protocol_send_name(socket, name);
|
||||
|
||||
/* Get password */
|
||||
if (client_data->password[0] == 0 &&
|
||||
prompt(client, "Password: ", client_data->password, sizeof(client_data->password), false) == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
/* Clear screen */
|
||||
guac_terminal_write_all(stdout_fd, "\x1B[H\x1B[J", 6);
|
||||
|
||||
/* Open SSH session */
|
||||
client_data->session = ssh_new();
|
||||
if (client_data->session == NULL) {
|
||||
guac_protocol_send_error(socket, "Unable to create SSH session.");
|
||||
guac_socket_flush(socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set session options */
|
||||
ssh_options_set(client_data->session, SSH_OPTIONS_HOST, client_data->hostname);
|
||||
ssh_options_set(client_data->session, SSH_OPTIONS_PORT, &(client_data->port));
|
||||
ssh_options_set(client_data->session, SSH_OPTIONS_USER, client_data->username);
|
||||
|
||||
/* Connect */
|
||||
if (ssh_connect(client_data->session) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to connect via SSH.");
|
||||
guac_socket_flush(socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Authenticate */
|
||||
if (ssh_userauth_password(client_data->session, NULL, client_data->password) != SSH_AUTH_SUCCESS) {
|
||||
guac_protocol_send_error(socket, "SSH auth failed.");
|
||||
guac_socket_flush(socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Open channel for terminal */
|
||||
client_data->term_channel = channel_new(client_data->session);
|
||||
if (client_data->term_channel == NULL) {
|
||||
guac_protocol_send_error(socket, "Unable to open channel.");
|
||||
guac_socket_flush(socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Open session for channel */
|
||||
if (channel_open_session(client_data->term_channel) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to open channel session.");
|
||||
guac_socket_flush(socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Request PTY */
|
||||
if (channel_request_pty_size(client_data->term_channel, "linux",
|
||||
client_data->term->term_width, client_data->term->term_height) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to allocate PTY for channel.");
|
||||
guac_socket_flush(socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Request shell */
|
||||
if (channel_request_shell(client_data->term_channel) != SSH_OK) {
|
||||
guac_protocol_send_error(socket, "Unable to associate shell with PTY.");
|
||||
guac_socket_flush(socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Logged in */
|
||||
guac_client_log_info(client, "SSH connection successful.");
|
||||
|
||||
/* Start input thread */
|
||||
if (pthread_create(&(input_thread), NULL, ssh_input_thread, (void*) client)) {
|
||||
guac_client_log_error(client, "Unable to start SSH input thread");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* While data available, write to terminal */
|
||||
while (channel_is_open(client_data->term_channel)
|
||||
&& !channel_is_eof(client_data->term_channel)) {
|
||||
|
||||
/* Repeat read if necessary */
|
||||
if ((bytes_read = channel_read(client_data->term_channel, buffer, sizeof(buffer), 0)) == SSH_AGAIN)
|
||||
continue;
|
||||
|
||||
/* Attempt to write data received. Exit on failure. */
|
||||
if (bytes_read > 0) {
|
||||
int written = guac_terminal_write_all(stdout_fd, buffer, bytes_read);
|
||||
if (written < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Wait for input thread to die */
|
||||
pthread_join(input_thread, NULL);
|
||||
|
||||
guac_client_log_info(client, "SSH connection ended.");
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
856
protocols/ssh/src/terminal.c
Normal file
856
protocols/ssh/src/terminal.c
Normal file
@ -0,0 +1,856 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Muehlner <dagger10k@users.sourceforge.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/error.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "buffer.h"
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
#include "terminal.h"
|
||||
#include "terminal_handlers.h"
|
||||
|
||||
void guac_terminal_reset(guac_terminal* term) {
|
||||
|
||||
int row;
|
||||
|
||||
/* Set current state */
|
||||
term->char_handler = guac_terminal_echo;
|
||||
term->active_char_set = 0;
|
||||
term->char_mapping[0] =
|
||||
term->char_mapping[1] = NULL;
|
||||
|
||||
/* Reset cursor location */
|
||||
term->cursor_row = term->visible_cursor_row = term->saved_cursor_row = 0;
|
||||
term->cursor_col = term->visible_cursor_col = term->saved_cursor_col = 0;
|
||||
|
||||
/* Clear scrollback, buffer, and scoll region */
|
||||
term->buffer->top = 0;
|
||||
term->buffer->length = 0;
|
||||
term->scroll_start = 0;
|
||||
term->scroll_end = term->term_height - 1;
|
||||
term->scroll_offset = 0;
|
||||
|
||||
/* Reset flags */
|
||||
term->text_selected = false;
|
||||
term->application_cursor_keys = false;
|
||||
term->automatic_carriage_return = false;
|
||||
term->insert_mode = false;
|
||||
|
||||
/* Reset tabs */
|
||||
term->tab_interval = 8;
|
||||
memset(term->custom_tabs, 0, sizeof(term->custom_tabs));
|
||||
|
||||
/* Clear terminal */
|
||||
for (row=0; row<term->term_height; row++)
|
||||
guac_terminal_set_columns(term, row, 0, term->term_width, &(term->default_char));
|
||||
|
||||
}
|
||||
|
||||
guac_terminal* guac_terminal_create(guac_client* client,
|
||||
const char* font_name, int font_size,
|
||||
int width, int height) {
|
||||
|
||||
guac_terminal_char default_char = {
|
||||
.value = 0,
|
||||
.attributes = {
|
||||
.foreground = 7,
|
||||
.background = 0,
|
||||
.bold = false,
|
||||
.reverse = false,
|
||||
.underscore = false
|
||||
}};
|
||||
|
||||
guac_terminal* term = malloc(sizeof(guac_terminal));
|
||||
term->client = client;
|
||||
|
||||
/* Init buffer */
|
||||
term->buffer = guac_terminal_buffer_alloc(1000, &default_char);
|
||||
|
||||
/* Init display */
|
||||
term->display = guac_terminal_display_alloc(client,
|
||||
font_name, font_size,
|
||||
default_char.attributes.foreground,
|
||||
default_char.attributes.background);
|
||||
|
||||
/* Init terminal state */
|
||||
term->current_attributes = default_char.attributes;
|
||||
term->default_char = default_char;
|
||||
|
||||
term->term_width = width / term->display->char_width;
|
||||
term->term_height = height / term->display->char_height;
|
||||
|
||||
/* Open STDOUT pipe */
|
||||
if (pipe(term->stdout_pipe_fd)) {
|
||||
guac_error = GUAC_STATUS_SEE_ERRNO;
|
||||
guac_error_message = "Unable to open pipe for STDOUT";
|
||||
free(term);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Open STDIN pipe */
|
||||
if (pipe(term->stdin_pipe_fd)) {
|
||||
guac_error = GUAC_STATUS_SEE_ERRNO;
|
||||
guac_error_message = "Unable to open pipe for STDIN";
|
||||
free(term);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Init terminal lock */
|
||||
pthread_mutex_init(&(term->lock), NULL);
|
||||
|
||||
/* Size display */
|
||||
guac_terminal_display_resize(term->display,
|
||||
term->term_width, term->term_height);
|
||||
|
||||
/* Init terminal */
|
||||
guac_terminal_reset(term);
|
||||
|
||||
return term;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_free(guac_terminal* term) {
|
||||
|
||||
/* Close terminal output pipe */
|
||||
close(term->stdout_pipe_fd[1]);
|
||||
close(term->stdout_pipe_fd[0]);
|
||||
|
||||
/* Close user input pipe */
|
||||
close(term->stdin_pipe_fd[1]);
|
||||
close(term->stdin_pipe_fd[0]);
|
||||
|
||||
/* Free display */
|
||||
guac_terminal_display_free(term->display);
|
||||
|
||||
/* Free buffer */
|
||||
guac_terminal_buffer_free(term->buffer);
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_set(guac_terminal* term, int row, int col, int codepoint) {
|
||||
|
||||
/* Build character with current attributes */
|
||||
guac_terminal_char guac_char;
|
||||
guac_char.value = codepoint;
|
||||
guac_char.attributes = term->current_attributes;
|
||||
|
||||
guac_terminal_set_columns(term, row, col, col, &guac_char);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_commit_cursor(guac_terminal* term) {
|
||||
|
||||
guac_terminal_char* guac_char;
|
||||
|
||||
guac_terminal_buffer_row* old_row;
|
||||
guac_terminal_buffer_row* new_row;
|
||||
|
||||
/* If no change, done */
|
||||
if (term->visible_cursor_row == term->cursor_row && term->visible_cursor_col == term->cursor_col)
|
||||
return;
|
||||
|
||||
/* Get old and new rows with cursor */
|
||||
new_row = guac_terminal_buffer_get_row(term->buffer, term->cursor_row, term->cursor_col+1);
|
||||
old_row = guac_terminal_buffer_get_row(term->buffer, term->visible_cursor_row, term->visible_cursor_col+1);
|
||||
|
||||
/* Clear cursor */
|
||||
guac_char = &(old_row->characters[term->visible_cursor_col]);
|
||||
guac_char->attributes.cursor = false;
|
||||
guac_terminal_display_set_columns(term->display, term->visible_cursor_row + term->scroll_offset,
|
||||
term->visible_cursor_col, term->visible_cursor_col, guac_char);
|
||||
|
||||
/* Set cursor */
|
||||
guac_char = &(new_row->characters[term->cursor_col]);
|
||||
guac_char->attributes.cursor = true;
|
||||
guac_terminal_display_set_columns(term->display, term->cursor_row + term->scroll_offset,
|
||||
term->cursor_col, term->cursor_col, guac_char);
|
||||
|
||||
term->visible_cursor_row = term->cursor_row;
|
||||
term->visible_cursor_col = term->cursor_col;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_write(guac_terminal* term, const char* c, int size) {
|
||||
|
||||
while (size > 0) {
|
||||
term->char_handler(term, *(c++));
|
||||
size--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_scroll_up(guac_terminal* term,
|
||||
int start_row, int end_row, int amount) {
|
||||
|
||||
/* If scrolling entire display, update scroll offset */
|
||||
if (start_row == 0 && end_row == term->term_height - 1) {
|
||||
|
||||
/* Scroll up visibly */
|
||||
guac_terminal_display_copy_rows(term->display, start_row + amount, end_row, -amount);
|
||||
|
||||
/* Advance by scroll amount */
|
||||
term->buffer->top += amount;
|
||||
if (term->buffer->top >= term->buffer->available)
|
||||
term->buffer->top -= term->buffer->available;
|
||||
|
||||
term->buffer->length += amount;
|
||||
if (term->buffer->length > term->buffer->available)
|
||||
term->buffer->length = term->buffer->available;
|
||||
|
||||
/* Update cursor location if within region */
|
||||
if (term->visible_cursor_row >= start_row &&
|
||||
term->visible_cursor_row <= end_row)
|
||||
term->visible_cursor_row -= amount;
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, just copy row data upwards */
|
||||
else
|
||||
guac_terminal_copy_rows(term, start_row + amount, end_row, -amount);
|
||||
|
||||
/* Clear new area */
|
||||
guac_terminal_clear_range(term,
|
||||
end_row - amount + 1, 0,
|
||||
end_row, term->term_width - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_terminal_scroll_down(guac_terminal* term,
|
||||
int start_row, int end_row, int amount) {
|
||||
|
||||
guac_terminal_copy_rows(term, start_row, end_row - amount, amount);
|
||||
|
||||
/* Clear new area */
|
||||
guac_terminal_clear_range(term,
|
||||
start_row, 0,
|
||||
start_row + amount - 1, term->term_width - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_terminal_clear_columns(guac_terminal* term,
|
||||
int row, int start_col, int end_col) {
|
||||
|
||||
/* Build space */
|
||||
guac_terminal_char blank;
|
||||
blank.value = 0;
|
||||
blank.attributes = term->current_attributes;
|
||||
|
||||
/* Clear */
|
||||
guac_terminal_set_columns(term,
|
||||
row, start_col, end_col, &blank);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_clear_range(guac_terminal* term,
|
||||
int start_row, int start_col,
|
||||
int end_row, int end_col) {
|
||||
|
||||
/* If not at far left, must clear sub-region to far right */
|
||||
if (start_col > 0) {
|
||||
|
||||
/* Clear from start_col to far right */
|
||||
guac_terminal_clear_columns(term,
|
||||
start_row, start_col, term->term_width - 1);
|
||||
|
||||
/* One less row to clear */
|
||||
start_row++;
|
||||
}
|
||||
|
||||
/* If not at far right, must clear sub-region to far left */
|
||||
if (end_col < term->term_width - 1) {
|
||||
|
||||
/* Clear from far left to end_col */
|
||||
guac_terminal_clear_columns(term, end_row, 0, end_col);
|
||||
|
||||
/* One less row to clear */
|
||||
end_row--;
|
||||
|
||||
}
|
||||
|
||||
/* Remaining region now guaranteed rectangular. Clear, if possible */
|
||||
if (start_row <= end_row) {
|
||||
|
||||
int row;
|
||||
for (row=start_row; row<=end_row; row++) {
|
||||
|
||||
/* Clear entire row */
|
||||
guac_terminal_clear_columns(term, row, 0, term->term_width - 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_scroll_display_down(guac_terminal* terminal,
|
||||
int scroll_amount) {
|
||||
|
||||
int start_row, end_row;
|
||||
int dest_row;
|
||||
int row, column;
|
||||
|
||||
/* Limit scroll amount by size of scrollback buffer */
|
||||
if (scroll_amount > terminal->scroll_offset)
|
||||
scroll_amount = terminal->scroll_offset;
|
||||
|
||||
/* If not scrolling at all, don't bother trying */
|
||||
if (scroll_amount <= 0)
|
||||
return;
|
||||
|
||||
/* Shift screen up */
|
||||
if (terminal->term_height > scroll_amount)
|
||||
guac_terminal_display_copy_rows(terminal->display,
|
||||
scroll_amount, terminal->term_height - 1,
|
||||
-scroll_amount);
|
||||
|
||||
/* Advance by scroll amount */
|
||||
terminal->scroll_offset -= scroll_amount;
|
||||
|
||||
/* Get row range */
|
||||
end_row = terminal->term_height - terminal->scroll_offset - 1;
|
||||
start_row = end_row - scroll_amount + 1;
|
||||
dest_row = terminal->term_height - scroll_amount;
|
||||
|
||||
/* Draw new rows from scrollback */
|
||||
for (row=start_row; row<=end_row; row++) {
|
||||
|
||||
/* Get row from scrollback */
|
||||
guac_terminal_buffer_row* buffer_row =
|
||||
guac_terminal_buffer_get_row(terminal->buffer, row, 0);
|
||||
|
||||
/* Clear row */
|
||||
guac_terminal_display_set_columns(terminal->display,
|
||||
dest_row, 0, terminal->display->width, &(terminal->default_char));
|
||||
|
||||
/* Draw row */
|
||||
guac_terminal_char* current = buffer_row->characters;
|
||||
for (column=0; column<buffer_row->length; column++)
|
||||
guac_terminal_display_set_columns(terminal->display,
|
||||
dest_row, column, column, current++);
|
||||
|
||||
/* Next row */
|
||||
dest_row++;
|
||||
|
||||
}
|
||||
|
||||
guac_terminal_display_flush(terminal->display);
|
||||
guac_socket_flush(terminal->client->socket);
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_scroll_display_up(guac_terminal* terminal,
|
||||
int scroll_amount) {
|
||||
|
||||
int start_row, end_row;
|
||||
int dest_row;
|
||||
int row, column;
|
||||
|
||||
|
||||
/* Limit scroll amount by size of scrollback buffer */
|
||||
if (terminal->scroll_offset + scroll_amount > terminal->buffer->length - terminal->term_height)
|
||||
scroll_amount = terminal->buffer->length - terminal->scroll_offset - terminal->term_height;
|
||||
|
||||
/* If not scrolling at all, don't bother trying */
|
||||
if (scroll_amount <= 0)
|
||||
return;
|
||||
|
||||
/* Shift screen down */
|
||||
if (terminal->term_height > scroll_amount)
|
||||
guac_terminal_display_copy_rows(terminal->display,
|
||||
0, terminal->term_height - scroll_amount - 1,
|
||||
scroll_amount);
|
||||
|
||||
/* Advance by scroll amount */
|
||||
terminal->scroll_offset += scroll_amount;
|
||||
|
||||
/* Get row range */
|
||||
start_row = -terminal->scroll_offset;
|
||||
end_row = start_row + scroll_amount - 1;
|
||||
dest_row = 0;
|
||||
|
||||
/* Draw new rows from scrollback */
|
||||
for (row=start_row; row<=end_row; row++) {
|
||||
|
||||
/* Get row from scrollback */
|
||||
guac_terminal_buffer_row* buffer_row =
|
||||
guac_terminal_buffer_get_row(terminal->buffer, row, 0);
|
||||
|
||||
/* Clear row */
|
||||
guac_terminal_display_set_columns(terminal->display,
|
||||
dest_row, 0, terminal->display->width, &(terminal->default_char));
|
||||
|
||||
/* Draw row */
|
||||
guac_terminal_char* current = buffer_row->characters;
|
||||
for (column=0; column<buffer_row->length; column++)
|
||||
guac_terminal_display_set_columns(terminal->display,
|
||||
dest_row, column, column, current++);
|
||||
|
||||
/* Next row */
|
||||
dest_row++;
|
||||
|
||||
}
|
||||
|
||||
guac_terminal_display_flush(terminal->display);
|
||||
guac_socket_flush(terminal->client->socket);
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_select_redraw(guac_terminal* terminal) {
|
||||
|
||||
guac_terminal_display_select(terminal->display,
|
||||
terminal->selection_start_row + terminal->scroll_offset,
|
||||
terminal->selection_start_column,
|
||||
terminal->selection_end_row + terminal->scroll_offset,
|
||||
terminal->selection_end_column);
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_select_start(guac_terminal* terminal, int row, int column) {
|
||||
|
||||
terminal->selection_start_row =
|
||||
terminal->selection_end_row = row;
|
||||
|
||||
terminal->selection_start_column =
|
||||
terminal->selection_end_column = column;
|
||||
|
||||
terminal->text_selected = true;
|
||||
|
||||
guac_terminal_select_redraw(terminal);
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_select_update(guac_terminal* terminal, int row, int column) {
|
||||
|
||||
if (row != terminal->selection_end_row || column != terminal->selection_end_column) {
|
||||
terminal->selection_end_row = row;
|
||||
terminal->selection_end_column = column;
|
||||
|
||||
guac_terminal_select_redraw(terminal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int __guac_terminal_buffer_string(guac_terminal_buffer_row* row, int start, int end, char* string) {
|
||||
|
||||
int length = 0;
|
||||
int i;
|
||||
for (i=start; i<=end; i++) {
|
||||
|
||||
int codepoint = row->characters[i].value;
|
||||
|
||||
/* If not null (blank), add to string */
|
||||
if (codepoint != 0) {
|
||||
int bytes = guac_terminal_encode_utf8(codepoint, string);
|
||||
string += bytes;
|
||||
length += bytes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return length;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_select_end(guac_terminal* terminal, char* string) {
|
||||
|
||||
/* Deselect */
|
||||
terminal->text_selected = false;
|
||||
guac_terminal_display_commit_select(terminal->display);
|
||||
|
||||
guac_terminal_buffer_row* buffer_row;
|
||||
|
||||
int row;
|
||||
|
||||
int start_row, start_col;
|
||||
int end_row, end_col;
|
||||
|
||||
/* Ensure proper ordering of start and end coords */
|
||||
if (terminal->selection_start_row <= terminal->selection_end_row) {
|
||||
start_row = terminal->selection_start_row;
|
||||
start_col = terminal->selection_start_column;
|
||||
end_row = terminal->selection_end_row;
|
||||
end_col = terminal->selection_end_column;
|
||||
}
|
||||
else {
|
||||
end_row = terminal->selection_start_row;
|
||||
end_col = terminal->selection_start_column;
|
||||
start_row = terminal->selection_end_row;
|
||||
start_col = terminal->selection_end_column;
|
||||
}
|
||||
|
||||
/* If only one row, simply copy */
|
||||
buffer_row = guac_terminal_buffer_get_row(terminal->buffer, start_row, 0);
|
||||
if (end_row == start_row) {
|
||||
if (buffer_row->length - 1 < end_col)
|
||||
end_col = buffer_row->length - 1;
|
||||
string += __guac_terminal_buffer_string(buffer_row, start_col, end_col, string);
|
||||
}
|
||||
|
||||
/* Otherwise, copy multiple rows */
|
||||
else {
|
||||
|
||||
/* Store first row */
|
||||
string += __guac_terminal_buffer_string(buffer_row, start_col, buffer_row->length - 1, string);
|
||||
|
||||
/* Store all middle rows */
|
||||
for (row=start_row+1; row<end_row; row++) {
|
||||
|
||||
buffer_row = guac_terminal_buffer_get_row(terminal->buffer, row, 0);
|
||||
|
||||
*(string++) = '\n';
|
||||
string += __guac_terminal_buffer_string(buffer_row, 0, buffer_row->length - 1, string);
|
||||
|
||||
}
|
||||
|
||||
/* Store last row */
|
||||
buffer_row = guac_terminal_buffer_get_row(terminal->buffer, end_row, 0);
|
||||
if (buffer_row->length - 1 < end_col)
|
||||
end_col = buffer_row->length - 1;
|
||||
|
||||
*(string++) = '\n';
|
||||
string += __guac_terminal_buffer_string(buffer_row, 0, end_col, string);
|
||||
|
||||
}
|
||||
|
||||
/* Null terminator */
|
||||
*string = 0;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_copy_columns(guac_terminal* terminal, int row,
|
||||
int start_column, int end_column, int offset) {
|
||||
|
||||
guac_terminal_display_copy_columns(terminal->display, row + terminal->scroll_offset,
|
||||
start_column, end_column, offset);
|
||||
|
||||
guac_terminal_buffer_copy_columns(terminal->buffer, row,
|
||||
start_column, end_column, offset);
|
||||
|
||||
/* Update cursor location if within region */
|
||||
if (row == terminal->visible_cursor_row &&
|
||||
terminal->visible_cursor_col >= start_column &&
|
||||
terminal->visible_cursor_col <= end_column)
|
||||
terminal->visible_cursor_col += offset;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_copy_rows(guac_terminal* terminal,
|
||||
int start_row, int end_row, int offset) {
|
||||
|
||||
guac_terminal_display_copy_rows(terminal->display,
|
||||
start_row + terminal->scroll_offset, end_row + terminal->scroll_offset, offset);
|
||||
|
||||
guac_terminal_buffer_copy_rows(terminal->buffer,
|
||||
start_row, end_row, offset);
|
||||
|
||||
/* Update cursor location if within region */
|
||||
if (terminal->visible_cursor_row >= start_row &&
|
||||
terminal->visible_cursor_row <= end_row)
|
||||
terminal->visible_cursor_row += offset;
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_set_columns(guac_terminal* terminal, int row,
|
||||
int start_column, int end_column, guac_terminal_char* character) {
|
||||
|
||||
guac_terminal_display_set_columns(terminal->display, row + terminal->scroll_offset,
|
||||
start_column, end_column, character);
|
||||
|
||||
guac_terminal_buffer_set_columns(terminal->buffer, row,
|
||||
start_column, end_column, character);
|
||||
|
||||
/* If visible cursor in current row, preserve state */
|
||||
if (row == terminal->visible_cursor_row
|
||||
&& terminal->visible_cursor_col >= start_column
|
||||
&& terminal->visible_cursor_col <= end_column) {
|
||||
|
||||
/* Create copy of character with cursor attribute set */
|
||||
guac_terminal_char cursor_character = *character;
|
||||
cursor_character.attributes.cursor = true;
|
||||
|
||||
guac_terminal_display_set_columns(terminal->display, row + terminal->scroll_offset,
|
||||
terminal->visible_cursor_col, terminal->visible_cursor_col, &cursor_character);
|
||||
|
||||
guac_terminal_buffer_set_columns(terminal->buffer, row,
|
||||
terminal->visible_cursor_col, terminal->visible_cursor_col, &cursor_character);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void __guac_terminal_redraw_rect(guac_terminal* term, int start_row, int start_col, int end_row, int end_col) {
|
||||
|
||||
int row, col;
|
||||
|
||||
/* Redraw region */
|
||||
for (row=start_row; row<=end_row; row++) {
|
||||
|
||||
guac_terminal_buffer_row* buffer_row =
|
||||
guac_terminal_buffer_get_row(term->buffer, row - term->scroll_offset, 0);
|
||||
|
||||
/* Clear row */
|
||||
guac_terminal_display_set_columns(term->display,
|
||||
row, start_col, end_col, &(term->default_char));
|
||||
|
||||
/* Copy characters */
|
||||
for (col=start_col; col <= end_col && col < buffer_row->length; col++)
|
||||
guac_terminal_display_set_columns(term->display, row, col, col,
|
||||
&(buffer_row->characters[col]));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_resize(guac_terminal* term, int width, int height) {
|
||||
|
||||
/* If height is decreasing, shift display up */
|
||||
if (height < term->term_height) {
|
||||
|
||||
int shift_amount;
|
||||
|
||||
/* Get number of rows actually occupying terminal space */
|
||||
int used_height = term->buffer->length;
|
||||
if (used_height > term->term_height)
|
||||
used_height = term->term_height;
|
||||
|
||||
shift_amount = used_height - height;
|
||||
|
||||
/* If the new terminal bottom covers N rows, shift up N rows */
|
||||
if (shift_amount > 0) {
|
||||
|
||||
guac_terminal_display_copy_rows(term->display,
|
||||
shift_amount, term->display->height - 1, -shift_amount);
|
||||
|
||||
/* Update buffer top and cursor row based on shift */
|
||||
term->buffer->top += shift_amount;
|
||||
term->cursor_row -= shift_amount;
|
||||
term->visible_cursor_row -= shift_amount;
|
||||
|
||||
/* Redraw characters within old region */
|
||||
__guac_terminal_redraw_rect(term, height - shift_amount, 0, height-1, width-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Resize display */
|
||||
guac_terminal_display_flush(term->display);
|
||||
guac_terminal_display_resize(term->display, width, height);
|
||||
|
||||
/* Reraw any characters on right if widening */
|
||||
if (width > term->term_width)
|
||||
__guac_terminal_redraw_rect(term, 0, term->term_width-1, height-1, width-1);
|
||||
|
||||
/* If height is increasing, shift display down */
|
||||
if (height > term->term_height) {
|
||||
|
||||
/* If undisplayed rows exist in the buffer, shift them into view */
|
||||
if (term->term_height < term->buffer->length) {
|
||||
|
||||
/* If the new terminal bottom reveals N rows, shift down N rows */
|
||||
int shift_amount = height - term->term_height;
|
||||
|
||||
/* The maximum amount we can shift is the number of undisplayed rows */
|
||||
int max_shift = term->buffer->length - term->term_height;
|
||||
|
||||
if (shift_amount > max_shift)
|
||||
shift_amount = max_shift;
|
||||
|
||||
/* Update buffer top and cursor row based on shift */
|
||||
term->buffer->top -= shift_amount;
|
||||
term->cursor_row += shift_amount;
|
||||
term->visible_cursor_row += shift_amount;
|
||||
|
||||
/* If scrolled enough, use scroll to fulfill entire resize */
|
||||
if (term->scroll_offset >= shift_amount) {
|
||||
|
||||
term->scroll_offset -= shift_amount;
|
||||
|
||||
/* Draw characters from scroll at bottom */
|
||||
__guac_terminal_redraw_rect(term, term->term_height, 0, term->term_height + shift_amount - 1, width-1);
|
||||
|
||||
}
|
||||
|
||||
/* Otherwise, fulfill with as much scroll as possible */
|
||||
else {
|
||||
|
||||
/* Draw characters from scroll at bottom */
|
||||
__guac_terminal_redraw_rect(term, term->term_height, 0, term->term_height + term->scroll_offset - 1, width-1);
|
||||
|
||||
/* Update shift_amount and scroll based on new rows */
|
||||
shift_amount -= term->scroll_offset;
|
||||
term->scroll_offset = 0;
|
||||
|
||||
/* If anything remains, move screen as necessary */
|
||||
if (shift_amount > 0) {
|
||||
|
||||
guac_terminal_display_copy_rows(term->display,
|
||||
0, term->display->height - shift_amount - 1, shift_amount);
|
||||
|
||||
/* Draw characters at top from scroll */
|
||||
__guac_terminal_redraw_rect(term, 0, 0, shift_amount - 1, width-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} /* end if undisplayed rows exist */
|
||||
|
||||
}
|
||||
|
||||
/* Commit new dimensions */
|
||||
term->term_width = width;
|
||||
term->term_height = height;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_send_data(guac_terminal* term, const char* data, int length) {
|
||||
return guac_terminal_write_all(term->stdin_pipe_fd[1], data, length);
|
||||
}
|
||||
|
||||
int guac_terminal_send_string(guac_terminal* term, const char* data) {
|
||||
return guac_terminal_write_all(term->stdin_pipe_fd[1], data, strlen(data));
|
||||
}
|
||||
|
||||
int guac_terminal_sendf(guac_terminal* term, const char* format, ...) {
|
||||
|
||||
int written;
|
||||
|
||||
va_list ap;
|
||||
char buffer[1024];
|
||||
|
||||
/* Print to buffer */
|
||||
va_start(ap, format);
|
||||
written = vsnprintf(buffer, sizeof(buffer)-1, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (written < 0)
|
||||
return written;
|
||||
|
||||
/* Write to STDIN */
|
||||
return guac_terminal_write_all(term->stdin_pipe_fd[1], buffer, written);
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_set_tab(guac_terminal* term, int column) {
|
||||
|
||||
int i;
|
||||
|
||||
/* Search for available space, set if available */
|
||||
for (i=0; i<GUAC_TERMINAL_MAX_TABS; i++) {
|
||||
|
||||
/* Set tab if space free */
|
||||
if (term->custom_tabs[i] == 0) {
|
||||
term->custom_tabs[i] = column+1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_unset_tab(guac_terminal* term, int column) {
|
||||
|
||||
int i;
|
||||
|
||||
/* Search for given tab, unset if found */
|
||||
for (i=0; i<GUAC_TERMINAL_MAX_TABS; i++) {
|
||||
|
||||
/* Unset tab if found */
|
||||
if (term->custom_tabs[i] == column+1) {
|
||||
term->custom_tabs[i] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_terminal_clear_tabs(guac_terminal* term) {
|
||||
term->tab_interval = 0;
|
||||
memset(term->custom_tabs, 0, sizeof(term->custom_tabs));
|
||||
}
|
||||
|
||||
int guac_terminal_next_tab(guac_terminal* term, int column) {
|
||||
|
||||
int i;
|
||||
|
||||
/* Determine tab stop from interval */
|
||||
int tabstop;
|
||||
if (term->tab_interval != 0)
|
||||
tabstop = (column / term->tab_interval + 1) * term->tab_interval;
|
||||
else
|
||||
tabstop = term->term_width - 1;
|
||||
|
||||
/* Walk custom tabs, trying to find an earlier occurrence */
|
||||
for (i=0; i<GUAC_TERMINAL_MAX_TABS; i++) {
|
||||
|
||||
int custom_tabstop = term->custom_tabs[i] - 1;
|
||||
if (custom_tabstop != -1 && custom_tabstop > column && custom_tabstop < tabstop)
|
||||
tabstop = custom_tabstop;
|
||||
|
||||
}
|
||||
|
||||
return tabstop;
|
||||
}
|
||||
|
||||
|
926
protocols/ssh/src/terminal_handlers.c
Normal file
926
protocols/ssh/src/terminal_handlers.c
Normal file
@ -0,0 +1,926 @@
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libguac-client-ssh.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Michael Jumper.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "terminal.h"
|
||||
#include "terminal_handlers.h"
|
||||
#include "char_mappings.h"
|
||||
|
||||
/**
|
||||
* Response string sent when identification is requested.
|
||||
*/
|
||||
#define GUAC_TERMINAL_VT102_ID "\x1B[?6c"
|
||||
|
||||
/**
|
||||
* Arbitrary response to ENQ control character.
|
||||
*/
|
||||
#define GUAC_TERMINAL_ANSWERBACK "GUACAMOLE"
|
||||
|
||||
/**
|
||||
* Response which indicates the terminal is alive.
|
||||
*/
|
||||
#define GUAC_TERMINAL_OK "\x1B[0n"
|
||||
|
||||
int guac_terminal_echo(guac_terminal* term, char c) {
|
||||
|
||||
static int bytes_remaining = 0;
|
||||
static int codepoint = 0;
|
||||
|
||||
const int* char_mapping = term->char_mapping[term->active_char_set];
|
||||
|
||||
/* If using non-Unicode mapping, just map straight bytes */
|
||||
if (char_mapping != NULL) {
|
||||
codepoint = c;
|
||||
bytes_remaining = 0;
|
||||
}
|
||||
|
||||
/* 1-byte UTF-8 codepoint */
|
||||
else if ((c & 0x80) == 0x00) { /* 0xxxxxxx */
|
||||
codepoint = c & 0x7F;
|
||||
bytes_remaining = 0;
|
||||
}
|
||||
|
||||
/* 2-byte UTF-8 codepoint */
|
||||
else if ((c & 0xE0) == 0xC0) { /* 110xxxxx */
|
||||
codepoint = c & 0x1F;
|
||||
bytes_remaining = 1;
|
||||
}
|
||||
|
||||
/* 3-byte UTF-8 codepoint */
|
||||
else if ((c & 0xF0) == 0xE0) { /* 1110xxxx */
|
||||
codepoint = c & 0x0F;
|
||||
bytes_remaining = 2;
|
||||
}
|
||||
|
||||
/* 4-byte UTF-8 codepoint */
|
||||
else if ((c & 0xF8) == 0xF0) { /* 11110xxx */
|
||||
codepoint = c & 0x07;
|
||||
bytes_remaining = 3;
|
||||
}
|
||||
|
||||
/* Continuation of UTF-8 codepoint */
|
||||
else if ((c & 0xC0) == 0x80) { /* 10xxxxxx */
|
||||
codepoint = (codepoint << 6) | (c & 0x3F);
|
||||
bytes_remaining--;
|
||||
}
|
||||
|
||||
/* Unrecognized prefix */
|
||||
else {
|
||||
codepoint = '?';
|
||||
bytes_remaining = 0;
|
||||
}
|
||||
|
||||
/* If we need more bytes, wait for more bytes */
|
||||
if (bytes_remaining != 0)
|
||||
return 0;
|
||||
|
||||
switch (codepoint) {
|
||||
|
||||
/* Enquiry */
|
||||
case 0x05:
|
||||
guac_terminal_send_string(term, GUAC_TERMINAL_ANSWERBACK);
|
||||
break;
|
||||
|
||||
/* Bell */
|
||||
case 0x07:
|
||||
break;
|
||||
|
||||
/* Backspace */
|
||||
case 0x08:
|
||||
if (term->cursor_col >= 1)
|
||||
term->cursor_col--;
|
||||
break;
|
||||
|
||||
/* Tab */
|
||||
case 0x09:
|
||||
term->cursor_col = guac_terminal_next_tab(term, term->cursor_col);
|
||||
break;
|
||||
|
||||
/* Line feed / VT / FF */
|
||||
case '\n':
|
||||
case 0x0B: /* VT */
|
||||
case 0x0C: /* FF */
|
||||
term->cursor_row++;
|
||||
|
||||
/* Scroll up if necessary */
|
||||
if (term->cursor_row > term->scroll_end) {
|
||||
term->cursor_row = term->scroll_end;
|
||||
|
||||
/* Scroll up by one row */
|
||||
guac_terminal_scroll_up(term, term->scroll_start,
|
||||
term->scroll_end, 1);
|
||||
|
||||
}
|
||||
|
||||
/* If automatic carriage return, fall through to CR handler */
|
||||
if (!term->automatic_carriage_return)
|
||||
break;
|
||||
|
||||
/* Carriage return */
|
||||
case '\r':
|
||||
term->cursor_col = 0;
|
||||
break;
|
||||
|
||||
/* SO (activates character set G1) */
|
||||
case 0x0E:
|
||||
term->active_char_set = 1;
|
||||
break;
|
||||
|
||||
/* SI (activates character set G0) */
|
||||
case 0x0F:
|
||||
term->active_char_set = 0;
|
||||
break;
|
||||
|
||||
/* ESC */
|
||||
case 0x1B:
|
||||
term->char_handler = guac_terminal_escape;
|
||||
break;
|
||||
|
||||
/* CSI */
|
||||
case 0x9B:
|
||||
term->char_handler = guac_terminal_csi;
|
||||
break;
|
||||
|
||||
/* DEL (ignored) */
|
||||
case 0x7F:
|
||||
break;
|
||||
|
||||
/* Displayable chars */
|
||||
default:
|
||||
|
||||
/* Don't bother handling control chars if unknown */
|
||||
if (codepoint < 0x20)
|
||||
break;
|
||||
|
||||
/* Translate mappable codepoints to whatever codepoint is mapped */
|
||||
if (codepoint >= 0x20 && codepoint <= 0xFF && char_mapping != NULL)
|
||||
codepoint = char_mapping[codepoint - 0x20];
|
||||
|
||||
/* Wrap if necessary */
|
||||
if (term->cursor_col >= term->term_width) {
|
||||
term->cursor_col = 0;
|
||||
term->cursor_row++;
|
||||
}
|
||||
|
||||
/* Scroll up if necessary */
|
||||
if (term->cursor_row > term->scroll_end) {
|
||||
term->cursor_row = term->scroll_end;
|
||||
|
||||
/* Scroll up by one row */
|
||||
guac_terminal_scroll_up(term, term->scroll_start,
|
||||
term->scroll_end, 1);
|
||||
|
||||
}
|
||||
|
||||
/* If insert mode, shift other characters right by 1 */
|
||||
if (term->insert_mode)
|
||||
guac_terminal_copy_columns(term, term->cursor_row,
|
||||
term->cursor_col, term->term_width-2, 1);
|
||||
|
||||
/* Write character */
|
||||
guac_terminal_set(term,
|
||||
term->cursor_row,
|
||||
term->cursor_col,
|
||||
codepoint);
|
||||
|
||||
/* Advance cursor */
|
||||
term->cursor_col++;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_escape(guac_terminal* term, char c) {
|
||||
|
||||
switch (c) {
|
||||
|
||||
case '(':
|
||||
term->char_handler = guac_terminal_g0_charset;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
term->char_handler = guac_terminal_g1_charset;
|
||||
break;
|
||||
|
||||
case ']':
|
||||
term->char_handler = guac_terminal_osc;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
term->char_handler = guac_terminal_csi;
|
||||
break;
|
||||
|
||||
case '#':
|
||||
term->char_handler = guac_terminal_ctrl_func;
|
||||
break;
|
||||
|
||||
/* Save Cursor (DECSC) */
|
||||
case '7':
|
||||
term->saved_cursor_row = term->cursor_row;
|
||||
term->saved_cursor_col = term->cursor_col;
|
||||
|
||||
term->char_handler = guac_terminal_echo;
|
||||
break;
|
||||
|
||||
/* Restore Cursor (DECRC) */
|
||||
case '8':
|
||||
|
||||
term->cursor_row = term->saved_cursor_row;
|
||||
if (term->cursor_row >= term->term_height)
|
||||
term->cursor_row = term->term_height - 1;
|
||||
|
||||
term->cursor_col = term->saved_cursor_col;
|
||||
if (term->cursor_col >= term->term_width)
|
||||
term->cursor_col = term->term_width - 1;
|
||||
|
||||
term->char_handler = guac_terminal_echo;
|
||||
break;
|
||||
|
||||
/* Index (IND) */
|
||||
case 'D':
|
||||
term->cursor_row++;
|
||||
|
||||
/* Scroll up if necessary */
|
||||
if (term->cursor_row > term->scroll_end) {
|
||||
term->cursor_row = term->scroll_end;
|
||||
|
||||
/* Scroll up by one row */
|
||||
guac_terminal_scroll_up(term, term->scroll_start,
|
||||
term->scroll_end, 1);
|
||||
|
||||
}
|
||||
|
||||
term->char_handler = guac_terminal_echo;
|
||||
break;
|
||||
|
||||
/* Next Line (NEL) */
|
||||
case 'E':
|
||||
term->cursor_col = 0;
|
||||
term->cursor_row++;
|
||||
|
||||
/* Scroll up if necessary */
|
||||
if (term->cursor_row > term->scroll_end) {
|
||||
term->cursor_row = term->scroll_end;
|
||||
|
||||
/* Scroll up by one row */
|
||||
guac_terminal_scroll_up(term, term->scroll_start,
|
||||
term->scroll_end, 1);
|
||||
|
||||
}
|
||||
|
||||
term->char_handler = guac_terminal_echo;
|
||||
break;
|
||||
|
||||
/* Set Tab (HTS) */
|
||||
case 'H':
|
||||
guac_terminal_set_tab(term, term->cursor_col);
|
||||
break;
|
||||
|
||||
/* Reverse Linefeed */
|
||||
case 'M':
|
||||
|
||||
term->cursor_row--;
|
||||
|
||||
/* Scroll down if necessary */
|
||||
if (term->cursor_row < term->scroll_start) {
|
||||
term->cursor_row = term->scroll_start;
|
||||
|
||||
/* Scroll down by one row */
|
||||
guac_terminal_scroll_down(term, term->scroll_start,
|
||||
term->scroll_end, 1);
|
||||
|
||||
}
|
||||
|
||||
term->char_handler = guac_terminal_echo;
|
||||
break;
|
||||
|
||||
/* DEC Identify */
|
||||
case 'Z':
|
||||
guac_terminal_send_string(term, GUAC_TERMINAL_VT102_ID);
|
||||
term->char_handler = guac_terminal_echo;
|
||||
break;
|
||||
|
||||
/* Reset */
|
||||
case 'c':
|
||||
guac_terminal_reset(term);
|
||||
break;
|
||||
|
||||
default:
|
||||
guac_client_log_info(term->client, "Unhandled ESC sequence: %c", c);
|
||||
term->char_handler = guac_terminal_echo;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a character mapping specifier (such as B, 0, U, or K),
|
||||
* returns the corresponding character mapping.
|
||||
*/
|
||||
static const int* __guac_terminal_get_char_mapping(char c) {
|
||||
|
||||
/* Translate character specifier to actual mapping */
|
||||
switch (c) {
|
||||
case 'B': return NULL;
|
||||
case '0': return vt100_map;
|
||||
case 'U': return null_map;
|
||||
case 'K': return user_map;
|
||||
}
|
||||
|
||||
/* Default to Unicode */
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_g0_charset(guac_terminal* term, char c) {
|
||||
|
||||
term->char_mapping[0] = __guac_terminal_get_char_mapping(c);
|
||||
term->char_handler = guac_terminal_echo;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_g1_charset(guac_terminal* term, char c) {
|
||||
|
||||
term->char_mapping[1] = __guac_terminal_get_char_mapping(c);
|
||||
term->char_handler = guac_terminal_echo;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the flag specified by the given number and mode. Used by the Set/Reset Mode
|
||||
* functions of the terminal.
|
||||
*/
|
||||
static bool* __guac_terminal_get_flag(guac_terminal* term, int num, char private_mode) {
|
||||
|
||||
if (private_mode == '?') {
|
||||
switch (num) {
|
||||
case 1: return &(term->application_cursor_keys); /* DECCKM */
|
||||
}
|
||||
}
|
||||
|
||||
else if (private_mode == 0) {
|
||||
switch (num) {
|
||||
case 4: return &(term->insert_mode); /* DECIM */
|
||||
case 20: return &(term->automatic_carriage_return); /* LF/NL */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Unknown flag */
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_csi(guac_terminal* term, char c) {
|
||||
|
||||
/* CSI function arguments */
|
||||
static int argc = 0;
|
||||
static int argv[16] = {0};
|
||||
|
||||
/* Sequence prefix, if any */
|
||||
static char private_mode_character = 0;
|
||||
|
||||
/* Argument building counter and buffer */
|
||||
static int argv_length = 0;
|
||||
static char argv_buffer[256];
|
||||
|
||||
/* Digits get concatenated into argv */
|
||||
if (c >= '0' && c <= '9') {
|
||||
|
||||
/* Concatenate digit if there is space in buffer */
|
||||
if (argv_length < sizeof(argv_buffer)-1)
|
||||
argv_buffer[argv_length++] = c;
|
||||
|
||||
}
|
||||
|
||||
/* Specific non-digits stop the parameter, and possibly the sequence */
|
||||
else if ((c >= 0x40 && c <= 0x7E) || c == ';') {
|
||||
|
||||
int i, row, col, amount;
|
||||
bool* flag;
|
||||
|
||||
/* At most 16 parameters */
|
||||
if (argc < 16) {
|
||||
|
||||
/* Finish parameter */
|
||||
argv_buffer[argv_length] = 0;
|
||||
argv[argc++] = atoi(argv_buffer);
|
||||
|
||||
/* Prepare for next parameter */
|
||||
argv_length = 0;
|
||||
|
||||
}
|
||||
|
||||
/* Handle CSI functions */
|
||||
switch (c) {
|
||||
|
||||
/* @: Insert characters (scroll right) */
|
||||
case '@':
|
||||
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Scroll right by amount */
|
||||
if (term->cursor_col + amount < term->term_width)
|
||||
guac_terminal_copy_columns(term, term->cursor_row,
|
||||
term->cursor_col, term->term_width - amount - 1,
|
||||
amount);
|
||||
|
||||
/* Clear left */
|
||||
guac_terminal_clear_columns(term, term->cursor_row,
|
||||
term->cursor_col, term->cursor_col + amount - 1);
|
||||
|
||||
break;
|
||||
|
||||
/* A: Move up */
|
||||
case 'A':
|
||||
|
||||
/* Get move amount */
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Move cursor */
|
||||
term->cursor_row -= amount;
|
||||
if (term->cursor_row < 0)
|
||||
term->cursor_row = 0;
|
||||
|
||||
break;
|
||||
|
||||
/* B: Move down */
|
||||
case 'e':
|
||||
case 'B':
|
||||
|
||||
/* Get move amount */
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Move cursor */
|
||||
term->cursor_row += amount;
|
||||
if (term->cursor_row >= term->term_height)
|
||||
term->cursor_row = term->term_height - 1;
|
||||
|
||||
break;
|
||||
|
||||
/* C: Move right */
|
||||
case 'a':
|
||||
case 'C':
|
||||
|
||||
/* Get move amount */
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Move cursor */
|
||||
term->cursor_col += amount;
|
||||
if (term->cursor_col >= term->term_width)
|
||||
term->cursor_col = term->term_width - 1;
|
||||
|
||||
break;
|
||||
|
||||
/* D: Move left */
|
||||
case 'D':
|
||||
|
||||
/* Get move amount */
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Move cursor */
|
||||
term->cursor_col -= amount;
|
||||
if (term->cursor_col < 0)
|
||||
term->cursor_col = 0;
|
||||
|
||||
break;
|
||||
|
||||
/* E: Move cursor down given number rows, column 1 */
|
||||
case 'E':
|
||||
|
||||
/* Get move amount */
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Move cursor */
|
||||
term->cursor_row += amount;
|
||||
if (term->cursor_row >= term->term_height)
|
||||
term->cursor_row = term->term_height - 1;
|
||||
|
||||
/* Reset to column 1 */
|
||||
term->cursor_col = 0;
|
||||
|
||||
break;
|
||||
|
||||
/* F: Move cursor up given number rows, column 1 */
|
||||
case 'F':
|
||||
|
||||
/* Get move amount */
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Move cursor */
|
||||
term->cursor_row -= amount;
|
||||
if (term->cursor_row < 0)
|
||||
term->cursor_row = 0;
|
||||
|
||||
/* Reset to column 1 */
|
||||
term->cursor_col = 0;
|
||||
|
||||
break;
|
||||
|
||||
/* G: Move cursor, current row */
|
||||
case '`':
|
||||
case 'G':
|
||||
col = argv[0]; if (col != 0) col--;
|
||||
term->cursor_col = col;
|
||||
break;
|
||||
|
||||
/* H: Move cursor */
|
||||
case 'f':
|
||||
case 'H':
|
||||
|
||||
row = argv[0]; if (row != 0) row--;
|
||||
col = argv[1]; if (col != 0) col--;
|
||||
|
||||
term->cursor_row = row;
|
||||
term->cursor_col = col;
|
||||
break;
|
||||
|
||||
/* J: Erase display */
|
||||
case 'J':
|
||||
|
||||
/* Erase from cursor to end of display */
|
||||
if (argv[0] == 0)
|
||||
guac_terminal_clear_range(term,
|
||||
term->cursor_row, term->cursor_col,
|
||||
term->term_height-1, term->term_width-1);
|
||||
|
||||
/* Erase from start to cursor */
|
||||
else if (argv[0] == 1)
|
||||
guac_terminal_clear_range(term,
|
||||
0, 0,
|
||||
term->cursor_row, term->cursor_col);
|
||||
|
||||
/* Entire screen */
|
||||
else if (argv[0] == 2 || argv[0] == 3)
|
||||
guac_terminal_clear_range(term,
|
||||
0, 0, term->term_height - 1, term->term_width - 1);
|
||||
|
||||
break;
|
||||
|
||||
/* K: Erase line */
|
||||
case 'K':
|
||||
|
||||
/* Erase from cursor to end of line */
|
||||
if (argv[0] == 0)
|
||||
guac_terminal_clear_columns(term, term->cursor_row,
|
||||
term->cursor_col, term->term_width - 1);
|
||||
|
||||
/* Erase from start to cursor */
|
||||
else if (argv[0] == 1)
|
||||
guac_terminal_clear_columns(term, term->cursor_row,
|
||||
0, term->cursor_col);
|
||||
|
||||
/* Erase line */
|
||||
else if (argv[0] == 2)
|
||||
guac_terminal_clear_columns(term, term->cursor_row,
|
||||
0, term->term_width - 1);
|
||||
|
||||
break;
|
||||
|
||||
/* L: Insert blank lines (scroll down) */
|
||||
case 'L':
|
||||
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
guac_terminal_scroll_down(term,
|
||||
term->cursor_row, term->scroll_end, amount);
|
||||
|
||||
break;
|
||||
|
||||
/* M: Delete lines (scroll up) */
|
||||
case 'M':
|
||||
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
guac_terminal_scroll_up(term,
|
||||
term->cursor_row, term->scroll_end, amount);
|
||||
|
||||
break;
|
||||
|
||||
/* P: Delete characters (scroll left) */
|
||||
case 'P':
|
||||
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Scroll left by amount */
|
||||
if (term->cursor_col + amount < term->term_width)
|
||||
guac_terminal_copy_columns(term, term->cursor_row,
|
||||
term->cursor_col + amount, term->term_width - 1,
|
||||
-amount);
|
||||
|
||||
/* Clear right */
|
||||
guac_terminal_clear_columns(term, term->cursor_row,
|
||||
term->term_width - amount, term->term_width - 1);
|
||||
|
||||
break;
|
||||
|
||||
/* X: Erase characters (no scroll) */
|
||||
case 'X':
|
||||
|
||||
amount = argv[0];
|
||||
if (amount == 0) amount = 1;
|
||||
|
||||
/* Clear characters */
|
||||
guac_terminal_clear_columns(term, term->cursor_row,
|
||||
term->cursor_col, term->cursor_col + amount - 1);
|
||||
|
||||
break;
|
||||
|
||||
/* ]: Linux Private CSI */
|
||||
case ']':
|
||||
/* Explicitly ignored */
|
||||
break;
|
||||
|
||||
/* c: Identify */
|
||||
case 'c':
|
||||
if (argv[0] == 0 && private_mode_character == 0)
|
||||
guac_terminal_send_string(term, GUAC_TERMINAL_VT102_ID);
|
||||
break;
|
||||
|
||||
/* d: Move cursor, current col */
|
||||
case 'd':
|
||||
row = argv[0]; if (row != 0) row--;
|
||||
term->cursor_row = row;
|
||||
break;
|
||||
|
||||
/* g: Clear tab */
|
||||
case 'g':
|
||||
|
||||
/* Clear tab at current location */
|
||||
if (argv[0] == 0)
|
||||
guac_terminal_unset_tab(term, term->cursor_col);
|
||||
|
||||
/* Clear all tabs */
|
||||
else if (argv[0] == 3)
|
||||
guac_terminal_clear_tabs(term);
|
||||
|
||||
break;
|
||||
|
||||
/* h: Set Mode */
|
||||
case 'h':
|
||||
|
||||
/* Look up flag and set */
|
||||
flag = __guac_terminal_get_flag(term, argv[0], private_mode_character);
|
||||
if (flag != NULL)
|
||||
*flag = true;
|
||||
|
||||
break;
|
||||
|
||||
/* l: Reset Mode */
|
||||
case 'l':
|
||||
|
||||
/* Look up flag and clear */
|
||||
flag = __guac_terminal_get_flag(term, argv[0], private_mode_character);
|
||||
if (flag != NULL)
|
||||
*flag = false;
|
||||
|
||||
break;
|
||||
|
||||
/* m: Set graphics rendition */
|
||||
case 'm':
|
||||
|
||||
for (i=0; i<argc; i++) {
|
||||
|
||||
int value = argv[i];
|
||||
|
||||
/* Reset attributes */
|
||||
if (value == 0)
|
||||
term->current_attributes = term->default_char.attributes;
|
||||
|
||||
/* Bold */
|
||||
else if (value == 1)
|
||||
term->current_attributes.bold = true;
|
||||
|
||||
/* Underscore on */
|
||||
else if (value == 4)
|
||||
term->current_attributes.underscore = true;
|
||||
|
||||
/* Reverse video */
|
||||
else if (value == 7)
|
||||
term->current_attributes.reverse = true;
|
||||
|
||||
/* Normal intensity (not bold) */
|
||||
else if (value == 21 || value == 22)
|
||||
term->current_attributes.bold = false;
|
||||
|
||||
/* Reset underscore */
|
||||
else if (value == 24)
|
||||
term->current_attributes.underscore = false;
|
||||
|
||||
/* Reset reverse video */
|
||||
else if (value == 27)
|
||||
term->current_attributes.reverse = false;
|
||||
|
||||
/* Foreground */
|
||||
else if (value >= 30 && value <= 37)
|
||||
term->current_attributes.foreground = value - 30;
|
||||
|
||||
/* Underscore on, default foreground */
|
||||
else if (value == 38) {
|
||||
term->current_attributes.underscore = true;
|
||||
term->current_attributes.foreground =
|
||||
term->default_char.attributes.foreground;
|
||||
}
|
||||
|
||||
/* Underscore off, default foreground */
|
||||
else if (value == 39) {
|
||||
term->current_attributes.underscore = false;
|
||||
term->current_attributes.foreground =
|
||||
term->default_char.attributes.foreground;
|
||||
}
|
||||
|
||||
/* Background */
|
||||
else if (value >= 40 && value <= 47)
|
||||
term->current_attributes.background = value - 40;
|
||||
|
||||
/* Reset background */
|
||||
else if (value == 49)
|
||||
term->current_attributes.background =
|
||||
term->default_char.attributes.background;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* n: Status report */
|
||||
case 'n':
|
||||
|
||||
/* Device status report */
|
||||
if (argv[0] == 5 && private_mode_character == 0)
|
||||
guac_terminal_send_string(term, GUAC_TERMINAL_OK);
|
||||
|
||||
/* Cursor position report */
|
||||
else if (argv[0] == 6 && private_mode_character == 0)
|
||||
guac_terminal_sendf(term, "\x1B[%i;%iR", term->cursor_row+1, term->cursor_col+1);
|
||||
|
||||
break;
|
||||
|
||||
/* q: Set keyboard LEDs */
|
||||
case 'q':
|
||||
/* Explicitly ignored */
|
||||
break;
|
||||
|
||||
/* r: Set scrolling region */
|
||||
case 'r':
|
||||
|
||||
/* If parameters given, set region */
|
||||
if (argc == 2) {
|
||||
term->scroll_start = argv[0]-1;
|
||||
term->scroll_end = argv[1]-1;
|
||||
}
|
||||
|
||||
/* Otherwise, reset scrolling region */
|
||||
else {
|
||||
term->scroll_start = 0;
|
||||
term->scroll_end = term->term_height - 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* Save Cursor */
|
||||
case 's':
|
||||
term->saved_cursor_row = term->cursor_row;
|
||||
term->saved_cursor_col = term->cursor_col;
|
||||
break;
|
||||
|
||||
/* Restore Cursor */
|
||||
case 'u':
|
||||
|
||||
term->cursor_row = term->saved_cursor_row;
|
||||
if (term->cursor_row >= term->term_height)
|
||||
term->cursor_row = term->term_height - 1;
|
||||
|
||||
term->cursor_col = term->saved_cursor_col;
|
||||
if (term->cursor_col >= term->term_width)
|
||||
term->cursor_col = term->term_width - 1;
|
||||
|
||||
break;
|
||||
|
||||
|
||||
/* Warn of unhandled codes */
|
||||
default:
|
||||
if (c != ';') {
|
||||
|
||||
guac_client_log_info(term->client,
|
||||
"Unhandled CSI sequence: %c", c);
|
||||
|
||||
for (i=0; i<argc; i++)
|
||||
guac_client_log_info(term->client,
|
||||
" -> argv[%i] = %i", i, argv[i]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If not a semicolon, end of CSI sequence */
|
||||
if (c != ';') {
|
||||
term->char_handler = guac_terminal_echo;
|
||||
|
||||
/* Reset parameters */
|
||||
for (i=0; i<argc; i++)
|
||||
argv[i] = 0;
|
||||
|
||||
/* Reset private mode character */
|
||||
private_mode_character = 0;
|
||||
|
||||
/* Reset argument counters */
|
||||
argc = 0;
|
||||
argv_length = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Set private mode character if given and unset */
|
||||
else if (c >= 0x3A && c <= 0x3F && private_mode_character == 0)
|
||||
private_mode_character = c;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_terminal_osc(guac_terminal* term, char c) {
|
||||
/* TODO: Implement OSC */
|
||||
if (c == 0x9C || c == 0x5C || c == 0x07) /* ECMA-48 ST (String Terminator */
|
||||
term->char_handler = guac_terminal_echo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_terminal_ctrl_func(guac_terminal* term, char c) {
|
||||
|
||||
int row;
|
||||
|
||||
/* Build character with current attributes */
|
||||
guac_terminal_char guac_char;
|
||||
guac_char.value = 'E';
|
||||
guac_char.attributes = term->current_attributes;
|
||||
|
||||
switch (c) {
|
||||
|
||||
/* Alignment test (fill screen with E's) */
|
||||
case '8':
|
||||
|
||||
for (row=0; row<term->term_height; row++)
|
||||
guac_terminal_set_columns(term, row, 0, term->term_width-1, &guac_char);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
term->char_handler = guac_terminal_echo;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user