aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2007-11-21 05:32:39 +0000
committerKenny Root <kenny@the-b.org>2007-11-21 05:32:39 +0000
commitd6764b7763e7857273b65048b4eb37a3c65efade (patch)
tree4e84d4d9327d8a8de685fd0f181208c82e1cb9ad
parent4d94be3c05a341c18396f45945d86d61ca86dec4 (diff)
downloadconnectbot-d6764b7763e7857273b65048b4eb37a3c65efade.tar.gz
connectbot-d6764b7763e7857273b65048b4eb37a3c65efade.tar.bz2
connectbot-d6764b7763e7857273b65048b4eb37a3c65efade.zip
Merging back in the jcterm branch
-rw-r--r--LICENSE674
-rw-r--r--res/layout/secure_shell.xml8
-rw-r--r--src/com/jcraft/jcterm/Emulator.java416
-rw-r--r--src/com/jcraft/jcterm/EmulatorVT100.java634
-rw-r--r--src/com/jcraft/jcterm/Term.java80
-rw-r--r--src/de/mud/terminal/SoftFont.java1145
-rw-r--r--src/de/mud/terminal/VDUBuffer.java791
-rw-r--r--src/de/mud/terminal/VDUDisplay.java37
-rw-r--r--src/de/mud/terminal/VDUInput.java89
-rw-r--r--src/de/mud/terminal/vt320.java2722
-rw-r--r--src/org/theb/provider/HostDb.java18
-rw-r--r--src/org/theb/ssh/ConnectionThread.java30
-rw-r--r--src/org/theb/ssh/FeedbackUI.java25
-rw-r--r--src/org/theb/ssh/HostDbProvider.java18
-rw-r--r--src/org/theb/ssh/HostEditor.java18
-rw-r--r--src/org/theb/ssh/HostsList.java18
-rw-r--r--src/org/theb/ssh/InteractiveHostKeyVerifier.java18
-rw-r--r--src/org/theb/ssh/JCTerminalView.java329
-rw-r--r--src/org/theb/ssh/JTATerminalView.java323
-rw-r--r--src/org/theb/ssh/PasswordDialog.java18
-rw-r--r--src/org/theb/ssh/PreferencesDialog.java42
-rw-r--r--src/org/theb/ssh/SecureShell.java370
-rw-r--r--src/org/theb/ssh/ShellView.java77
-rw-r--r--src/org/theb/ssh/Terminal.java31
-rw-r--r--src/org/theb/ssh/TrileadConnectionThread.java164
25 files changed, 7739 insertions, 356 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/res/layout/secure_shell.xml b/res/layout/secure_shell.xml
index 0f47c70..9af5081 100644
--- a/res/layout/secure_shell.xml
+++ b/res/layout/secure_shell.xml
@@ -3,10 +3,16 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent">
+ <org.theb.ssh.TerminalView id="@+id/terminal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:textSize="8sp"
+ android:typeface="monospace" />
+<!--
<TextView id="@+id/output"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textSize="8sp"
android:typeface="monospace" />
-
+ -->
</RelativeLayout>
diff --git a/src/com/jcraft/jcterm/Emulator.java b/src/com/jcraft/jcterm/Emulator.java
new file mode 100644
index 0000000..7723738
--- /dev/null
+++ b/src/com/jcraft/jcterm/Emulator.java
@@ -0,0 +1,416 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/* JCTerm
+ * Copyright (C) 2002,2007 ymnk, JCraft,Inc.
+ *
+ * Written by: ymnk<ymnk@jcaft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jcterm;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+public abstract class Emulator{
+ Term term=null;
+ InputStream in=null;
+
+ public Emulator(Term term, InputStream in){
+ this.term=term;
+ this.in=in;
+ }
+
+ public abstract void start();
+
+ public abstract byte[] getCodeENTER();
+
+ public abstract byte[] getCodeUP();
+
+ public abstract byte[] getCodeDOWN();
+
+ public abstract byte[] getCodeRIGHT();
+
+ public abstract byte[] getCodeLEFT();
+
+ public abstract byte[] getCodeF1();
+
+ public abstract byte[] getCodeF2();
+
+ public abstract byte[] getCodeF3();
+
+ public abstract byte[] getCodeF4();
+
+ public abstract byte[] getCodeF5();
+
+ public abstract byte[] getCodeF6();
+
+ public abstract byte[] getCodeF7();
+
+ public abstract byte[] getCodeF8();
+
+ public abstract byte[] getCodeF9();
+
+ public abstract byte[] getCodeF10();
+
+ public abstract byte[] getCodeTAB();
+
+ public void reset(){
+ term_width=term.getColumnCount();
+ term_height=term.getRowCount();
+ char_width=term.getCharWidth();
+ char_height=term.getCharHeight();
+ region_y1=1;
+ region_y2=term_height;
+ }
+
+ byte[] buf=new byte[1024];
+ int bufs=0;
+ int buflen=0;
+
+ byte getChar() throws java.io.IOException{
+ if(buflen==0){
+ fillBuf();
+ }
+ buflen--;
+
+ // System.out.println("getChar: "+new Character((char)buf[bufs])+"["+Integer.toHexString(buf[bufs]&0xff)+"]");
+
+ return buf[bufs++];
+ }
+
+ void fillBuf() throws java.io.IOException{
+ buflen=bufs=0;
+ buflen=in.read(buf, bufs, buf.length-bufs);
+ /*
+ System.out.println("fillBuf: ");
+ for(int i=0; i<buflen; i++){
+ byte b=buf[i];
+ System.out.print(new Character((char)b)+"["+Integer.toHexString(b&0xff)+"], ");
+ }
+ System.out.println("");
+ */
+ if(buflen<=0){
+ buflen=0;
+ throw new IOException("fillBuf");
+ }
+ }
+
+ void pushChar(byte foo) throws java.io.IOException{
+ //System.out.println("pushChar: "+new Character((char)foo)+"["+Integer.toHexString(foo&0xff)+"]");
+ buflen++;
+ buf[--bufs]=foo;
+ }
+
+ int getASCII(int len) throws java.io.IOException{
+ //System.out.println("bufs="+bufs+", buflen="+buflen+", len="+len);
+ if(buflen==0){
+ fillBuf();
+ }
+ if(len>buflen)
+ len=buflen;
+ int foo=len;
+ byte tmp;
+ while(len>0){
+ tmp=buf[bufs++];
+ if(0x20<=tmp&&tmp<=0x7f){
+ buflen--;
+ len--;
+ continue;
+ }
+ bufs--;
+ break;
+ }
+ //System.out.println(" return "+(foo-len));
+ return foo-len;
+ }
+
+ protected int term_width=80;
+ protected int term_height=24;
+
+ protected int x=0;
+ protected int y=0;
+
+ protected int char_width;
+ protected int char_height;
+
+ private int region_y2;
+ private int region_y1;
+
+ protected int tab=8;
+
+ // Reverse scroll
+ protected void scroll_reverse(){
+ term.draw_cursor();
+ term.scroll_area(0, (region_y1-1)*char_height, term_width*char_width,
+ (region_y2-region_y1)*char_height, 0, char_height);
+ term.clear_area(x, y-char_height, term_width*char_width, y);
+ term.redraw(0, 0, term_width*char_width, term_height*char_height
+ -char_height);
+ //term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ // Normal scroll one line
+ protected void scroll_forward(){
+ term.draw_cursor();
+ term.scroll_area(0, (region_y1-1)*char_height, term_width*char_width,
+ (region_y2-region_y1+1)*char_height, 0, -char_height);
+ term.clear_area(0, region_y2*char_height-char_height,
+ term_width*char_width, region_y2*char_height);
+ term.redraw(0, (region_y1-1)*char_height, term_width*char_width, (region_y2
+ -region_y1+1)
+ *char_height);
+ term.draw_cursor();
+ }
+
+ // Save cursor position
+ protected void save_cursor(){
+ // TODO
+ //System.out.println("save current cursor position");
+ }
+
+ // Enable alternate character set
+ protected void ena_acs(){
+ // TODO
+ //System.out.println("enable alterate char set");
+ }
+
+ protected void exit_alt_charset_mode(){
+ // TODO
+ //System.out.println("end alternate character set (P)");
+ }
+
+ protected void enter_alt_charset_mode(){
+ // TODO
+ //System.out.println("start alternate character set (P)");
+ }
+
+ protected void reset_2string(){
+ // TODO
+ // rs2(reset string)
+ }
+
+ protected void exit_attribute_mode(){
+ // TODO
+ //System.out.println("turn off all attributes");
+ term.resetAllAttributes();
+ }
+
+ protected void exit_standout_mode(){
+ term.resetAllAttributes();
+ }
+
+ protected void exit_underline_mode(){
+ // TODO
+ }
+
+ protected void enter_bold_mode(){
+ term.setBold();
+ }
+
+ protected void enter_underline_mode(){
+ term.setUnderline();
+ }
+
+ protected void enter_reverse_mode(){
+ term.setReverse();
+ }
+
+ protected void change_scroll_region(int y1, int y2){
+ region_y1=y1;
+ region_y2=y2;
+ }
+
+ protected void cursor_address(int r, int c){
+ term.draw_cursor();
+ x=(c-1)*char_width;
+ y=r*char_height;
+ //System.out.println("setCourosr: "+x+" "+y);
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ protected void parm_down_cursor(int lines){
+ term.draw_cursor();
+ y+=(lines)*char_height;
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ protected void parm_left_cursor(int chars){
+ term.draw_cursor();
+ x-=(chars)*char_width;
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ protected void parm_right_cursor(int chars){
+ term.draw_cursor();
+ x+=(chars)*char_width;
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ protected void clr_eol(){
+ term.draw_cursor();
+ term.clear_area(x, y-char_height, term_width*char_width, y);
+ term.redraw(x, y-char_height, (term_width)*char_width-x, char_height);
+ term.draw_cursor();
+ }
+
+ protected void clr_bol(){
+ term.draw_cursor();
+ term.clear_area(0, y-char_height, x, y);
+ term.redraw(0, y-char_height, x, char_height);
+ term.draw_cursor();
+ }
+
+ protected void clr_eos(){
+ term.draw_cursor();
+ term.clear_area(x, y-char_height, term_width*char_width, term_height
+ *char_height);
+ term.redraw(x, y-char_height, term_width*char_width-x, term_height
+ *char_height-y+char_height);
+ term.draw_cursor();
+ }
+
+ protected void parm_up_cursor(int lines){
+ term.draw_cursor();
+ // x=0;
+ // y-=char_height;
+ y-=(lines)*char_height;
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ protected void bell(){
+ term.beep();
+ }
+
+ protected void tab(){
+ term.draw_cursor();
+ x=(((x/char_width)/tab+1)*tab*char_width);
+ if(x>=term_width*char_width){
+ x=0;
+ y+=char_height;
+ }
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ protected void carriage_return(){
+ term.draw_cursor();
+ x=0;
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ protected void cursor_left(){
+ term.draw_cursor();
+ x-=char_width;
+ if(x<0){
+ y-=char_height;
+ x=term_width*char_width-char_width;
+ }
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ protected void cursor_down(){
+ term.draw_cursor();
+ y+=char_height;
+ term.setCursor(x, y);
+ term.draw_cursor();
+
+ check_region();
+ }
+
+ private byte[] b2=new byte[2];
+ private byte[] b1=new byte[1];
+
+ protected void draw_text() throws java.io.IOException{
+
+ int rx;
+ int ry;
+ int w;
+ int h;
+
+ check_region();
+
+ rx=x;
+ ry=y;
+
+ byte b=getChar();
+ term.draw_cursor();
+ //System.out.print(new Character((char)b)+"["+Integer.toHexString(b&0xff)+"]");
+ if((b&0x80)!=0){
+ term.clear_area(x, y-char_height, x+char_width*2, y);
+ b2[0]=b;
+ b2[1]=getChar();
+ term.drawString(new String(b2, 0, 2, "EUC-JP"), x, y);
+ x+=char_width;
+ x+=char_width;
+ w=char_width*2;
+ h=char_height;
+ }
+ else{
+ pushChar(b);
+ int foo=getASCII(term_width-(x/char_width));
+ if(foo!=0){
+ //System.out.println("foo="+foo+" "+x+", "+(y-char_height)+" "+(x+foo*char_width)+" "+y+" "+buf+" "+bufs+" "+b+" "+buf[bufs-foo]);
+ //System.out.println("foo="+foo+" ["+new String(buf, bufs-foo, foo));
+ term.clear_area(x, y-char_height, x+foo*char_width, y);
+ term.drawBytes(buf, bufs-foo, foo, x, y);
+ }
+ else{
+ foo=1;
+ term.clear_area(x, y-char_height, x+foo*char_width, y);
+ b1[0]=getChar();
+ term.drawBytes(b1, 0, foo, x, y);
+ //System.out.print("["+Integer.toHexString(bar[0]&0xff)+"]");
+ }
+ x+=(char_width*foo);
+ w=char_width*foo;
+ h=char_height;
+ }
+ term.redraw(rx, ry-char_height, w, h);
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+
+ private void check_region(){
+ if(x>=term_width*char_width){
+ //System.out.println("!! "+new Character((char)b)+"["+Integer.toHexString(b&0xff)+"]");
+ x=0;
+ y+=char_height;
+ //System.out.println("@1: ry="+ry);
+ }
+
+ if(y>region_y2*char_height){
+ while(y>region_y2*char_height){
+ y-=char_height;
+ }
+ term.draw_cursor();
+ term.scroll_area(0, region_y1*char_height, term_width*char_width,
+ (region_y2-region_y1)*char_height, 0, -char_height);
+ term.clear_area(0, y-char_height, term_width*char_width, y);
+ term.redraw(0, 0, term_width*char_width, region_y2*char_height);
+ term.setCursor(x, y);
+ term.draw_cursor();
+ }
+ }
+}
diff --git a/src/com/jcraft/jcterm/EmulatorVT100.java b/src/com/jcraft/jcterm/EmulatorVT100.java
new file mode 100644
index 0000000..cf2f96a
--- /dev/null
+++ b/src/com/jcraft/jcterm/EmulatorVT100.java
@@ -0,0 +1,634 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/* JCTerm
+ * Copyright (C) 2002,2007 ymnk, JCraft,Inc.
+ *
+ * Written by: ymnk<ymnk@jcaft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jcterm;
+
+import java.io.InputStream;
+
+public class EmulatorVT100 extends Emulator{
+
+ public EmulatorVT100(Term term, InputStream in){
+ super(term, in);
+ }
+
+ public void setInputStream(InputStream in){
+ this.in=in;
+ }
+
+ public void setTerm(Term term){
+ this.term=term;
+ }
+
+ public void start(){
+ reset();
+
+ int[] intarg=new int[10];
+ int intargi=0;
+
+ x=0;
+ y=char_height;
+
+ byte b;
+
+ try{
+ while(true){
+
+ b=getChar();
+
+ //System.out.println("@0: "+ new Character((char)b)+"["+Integer.toHexString(b&0xff)+"]");
+
+ //System.out.println("@0: ry="+ry);
+
+ /*
+ outputs from infocmp on RedHat8.0
+ # Reconstructed via infocmp from file: /usr/share/terminfo/v/vt100
+ vt100|vt100-am|dec vt100 (w/advanced video),
+ am, msgr, xenl, xon,
+ cols#80, it#8, lines#24, vt#3,
+ acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+ bel=^G, blink=\E[5m$<2>, bold=\E[1m$<2>,
+ clear=\E[H\E[J$<50>, cr=^M, csr=\E[%i%p1%d;%p2%dr,
+ cub=\E[%p1%dD, cub1=^H, cud=\E[%p1%dB, cud1=^J,
+ cuf=\E[%p1%dC, cuf1=\E[C$<2>,
+ cup=\E[%i%p1%d;%p2%dH$<5>, cuu=\E[%p1%dA,
+ cuu1=\E[A$<2>, ed=\E[J$<50>, el=\E[K$<3>, el1=\E[1K$<3>,
+ enacs=\E(B\E)0, home=\E[H, ht=^I, hts=\EH, ind=^J, ka1=\EOq,
+ ka3=\EOs, kb2=\EOr, kbs=^H, kc1=\EOp, kc3=\EOn, kcub1=\EOD,
+ kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA, kent=\EOM, kf0=\EOy,
+ kf1=\EOP, kf10=\EOx, kf2=\EOQ, kf3=\EOR, kf4=\EOS, kf5=\EOt,
+ kf6=\EOu, kf7=\EOv, kf8=\EOl, kf9=\EOw, rc=\E8,
+ rev=\E[7m$<2>, ri=\EM$<5>, rmacs=^O, rmam=\E[?7l,
+ rmkx=\E[?1l\E>, rmso=\E[m$<2>, rmul=\E[m$<2>,
+ rs2=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h, sc=\E7,
+ sgr=\E[0%?%p1%p6%|%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;$<2>,
+ sgr0=\E[m\017$<2>, smacs=^N, smam=\E[?7h, smkx=\E[?1h\E=,
+ smso=\E[7m$<2>, smul=\E[4m$<2>, tbc=\E[3g,
+ */
+ /*
+ am terminal has automatic margnins
+ msgr safe to move while in standout mode
+ xenl newline ignored after 80 cols (concept)
+ xon terminal uses xon/xoff handshake
+ cols number of columns in a line
+ it tabs initially every # spaces
+ lines number of lines on screen of page
+ vt virstual terminal number(CB/unix)
+ acsc graphics charset pairs, based on vt100
+ bel bell
+ blink turn on blinking
+ bold turn on bold(extra bright) mode
+ clear clear screen and home cursor(P*)
+ cr carriage return (P)(P*)
+ csr change region to line #1 to line #2(P)
+ cub move #1 characters to the left (P)
+ cub1 move left one space
+ cud down #1 lines (P*)
+ cud1 down one line
+ cuf move to #1 characters to the right.
+ cuf1 non-destructive space (move right one space)
+ cup move to row #1 columns #2
+ cuu up #1 lines (P*)
+ cuu1 up one line
+ ed clear to end of screen (P*)
+ el clear to end of line (P)
+ el1 Clear to begining of line
+ enacs enable alterate char set
+ home home cursor (if no cup)
+ ht tab to next 8-space hardware tab stop
+ hts set a tab in every row, current columns
+ ind scroll text up
+ ka1 upper left of keypad
+ ka3 upper right of keypad
+ kb2 center of keypad
+ kbs backspace key
+ kc1 lower left of keypad
+ kc3 lower right of keypad
+ kcub1 left-arrow key
+ kcud1 down-arrow key
+ kcuf1 right-arrow key
+ kcuu1 up-arrow key
+ kent enter/sekd key
+ kf0 F0 function key
+ kf1 F1 function key
+ kf10 F10 function key
+ kf2 F2 function key
+ kf3 F3 function key
+ kf4 F4 function key
+ kf5 F5 function key
+ kf6 F6 function key
+ kf7 F7 function key
+ kf8 F8 function key
+ kf9 F9 function key
+ rc restore cursor to position of last save_cursor
+ rev turn on reverse video mode
+ ri scroll text down (P)
+ rmacs end alternate character set
+ rmam turn off automatic margins
+ rmkx leave 'keybroad_transmit' mode
+ rmso exit standout mode
+ rmul exit underline mode
+ rs2 reset string
+ sc save current cursor position (P)
+ sgr define video attribute #1-#9(PG9)
+ sgr0 turn off all attributes
+ smacs start alternate character set (P)
+ smam turn on automatic margins
+ smkx enter 'keyborad_transmit' mode
+ smso begin standout mode
+ smul begin underline mode
+ tbc clear all tab stops(P)
+ */
+ if(b==0){
+ continue;
+ }
+
+ if(b==0x1b){
+ b=getChar();
+
+ //System.out.println("@1: "+ new Character((char)b)+"["+Integer.toHexString(b&0xff)+"]");
+
+ if(b=='M'){ // sr \EM sr scroll text down (P)
+ scroll_reverse();
+ continue;
+ }
+
+ if(b=='D'){ // sf
+ scroll_forward();
+ continue;
+ }
+
+ if(b=='7'){
+ save_cursor();
+ continue;
+ }
+
+ if(b=='('){
+ b=getChar();
+ if(b=='B'){
+ b=getChar();
+ if(b==0x1b){
+ b=getChar();
+ if(b==')'){
+ b=getChar();
+ if(b=='0'){ // enacs
+ ena_acs();
+ continue;
+ }
+ else{
+ pushChar((byte)'0');
+ }
+ }
+ else{
+ pushChar((byte)')');
+ }
+ }
+ else{
+ pushChar((byte)0x1b);
+ }
+ }
+ else{
+ pushChar((byte)'B');
+ }
+ }
+
+ if(b=='>'){
+ b=getChar(); // 0x1b
+ b=getChar(); // '['
+ b=getChar(); // '?'
+ b=getChar(); // '3'
+ b=getChar(); // 'l'
+ b=getChar(); // 0x1b
+ b=getChar(); // '['
+ b=getChar(); // '?'
+ b=getChar(); // '4'
+ b=getChar(); // 'l'
+ b=getChar(); // 0x1b
+ b=getChar(); // '['
+ b=getChar(); // '?'
+ b=getChar(); // '5'
+ b=getChar(); // 'l'
+ b=getChar(); // 0x1b
+ b=getChar(); // '['
+ b=getChar(); // '?'
+ b=getChar(); // '7'
+ b=getChar(); // 'h'
+ b=getChar(); // 0x1b
+ b=getChar(); // '['
+ b=getChar(); // '?'
+ b=getChar(); // '8'
+ b=getChar(); // 'h'
+
+ reset_2string();
+ continue;
+ }
+
+ if(b!='['){
+ System.out.print("@11: "+new Character((char)b)+"["
+ +Integer.toHexString(b&0xff)+"]");
+ pushChar(b);
+ continue;
+ }
+
+ //System.out.print("@2: "+ new Character((char)b)+"["+Integer.toHexString(b&0xff)+"]");
+
+ intargi=0;
+ intarg[intargi]=0;
+ int digit=0;
+
+ while(true){
+ b=getChar();
+ //System.out.print("#"+new Character((char)b)+"["+Integer.toHexString(b&0xff)+"]");
+ if(b==';'){
+ if(digit>0){
+ intargi++;
+ intarg[intargi]=0;
+ digit=0;
+ }
+ continue;
+ }
+
+ if('0'<=b&&b<='9'){
+ intarg[intargi]=intarg[intargi]*10+(b-'0');
+ digit++;
+ continue;
+ }
+
+ pushChar(b);
+ break;
+ }
+
+ b=getChar();
+
+ //System.out.print("@4: "+ new Character((char)b)+"["+Integer.toHexString(b&0xff)+"]");
+
+ if(b=='m'){
+ /*
+ b=getChar();
+ if(b=='$'){
+ b=getChar(); // <
+ b=getChar(); // 2
+ b=getChar(); // >
+ }
+ else{
+ pushChar(b);
+ }
+ */
+
+ if(digit==0&&intargi==0){
+ b=getChar();
+ if(b==0x0f){ // sgr0
+ exit_attribute_mode();
+ continue;
+ }
+ else{ // rmso, rmul
+ exit_underline_mode();
+ exit_standout_mode();
+ pushChar(b);
+ continue;
+ }
+ }
+
+ for(int i=0; i<=intargi; i++){
+ Object fg=null;
+ Object bg=null;
+ Object tmp=null;
+
+ switch(intarg[i]){
+ case 0: // Reset all attributes
+ exit_standout_mode();
+ continue;
+ case 1: // Bright // bold
+ enter_bold_mode();
+ continue;
+ case 2: // Dim
+ break;
+ case 4: // Underline
+ enter_underline_mode();
+ continue;
+ case 5: // Blink
+ case 8: // Hidden
+ break;
+ case 7: // reverse
+ enter_reverse_mode();
+ continue;
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ tmp=term.getColor(intarg[i]-30);
+ if(tmp!=null)
+ fg=tmp;
+ break;
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ tmp=term.getColor(intarg[i]-40);
+ if(tmp!=null)
+ bg=tmp;
+ break;
+ default:
+ break;
+ }
+ if(fg!=null)
+ term.setForeGround(fg);
+ if(bg!=null)
+ term.setBackGround(bg);
+ }
+ //System.out.println("fg: "+fg+" bg: "+bg);
+ continue;
+ }
+
+ if(b=='r'){ // csr
+ change_scroll_region(intarg[0], intarg[1]);
+ //System.out.println("r: "+region_y1+", "+region_y2+", intargi="+intargi);
+ continue;
+ }
+
+ if(b=='H'){ // cup
+ /*
+ b=getChar();
+ if(b!='$'){ // home
+ pushChar(b);
+ }
+ else{
+ b=getChar(); // <
+ b=getChar(); // 5
+ b=getChar(); // >
+ }
+ */
+
+ if(digit==0&&intargi==0){
+ intarg[0]=intarg[1]=1;
+ }
+
+ //System.out.println("H: "+region_y1+", "+region_y2+", intargi="+intargi);
+ cursor_address(intarg[0], intarg[1]);
+ continue;
+ }
+
+ if(b=='B'){ // cud
+ parm_down_cursor(intarg[0]);
+ continue;
+ }
+
+ if(b=='D'){ // cub
+ parm_left_cursor(intarg[0]);
+ continue;
+ }
+
+ if(b=='C'){ // cuf
+ if(digit==0&&intargi==0){
+ intarg[0]=1;
+ }
+ parm_right_cursor(intarg[0]);
+ continue;
+ }
+
+ if(b=='K'){ // el
+ /*
+ b=getChar(); //
+ if(b=='$'){
+ b=getChar(); // <
+ b=getChar(); // 3
+ b=getChar(); // >
+ }
+ else{
+ pushChar(b);
+ }
+ */
+
+ if(digit==0&&intargi==0){ // el
+ clr_eol();
+ }
+ else{ // el1
+ clr_bol();
+ }
+ continue;
+ }
+
+ if(b=='J'){
+ //for(int i=0; i<intargi; i++){ System.out.print(intarg[i]+" ");}
+ //System.out.println(intarg[0]+"<- intargi="+intargi);
+ clr_eos();
+ continue;
+ }
+
+ if(b=='A'){ // cuu
+ if(digit==0&&intargi==0){
+ intarg[0]=1;
+ }
+ parm_up_cursor(intarg[0]);
+ continue;
+ }
+
+ if(b=='?'){
+ b=getChar();
+ if(b=='1'){
+ b=getChar();
+ if(b=='l'||b=='h'){
+ b=getChar();
+ if(b==0x1b){
+ b=getChar();
+ if(b=='>'|| // rmkx , leave 'keybroad_transmit' mode
+ b=='='){ // smkx , enter 'keyborad_transmit' mode
+ // TODO
+ continue;
+ }
+ }
+ }
+ else if(b=='h'){
+ b=getChar();
+ if(b==0x1b){
+ b=getChar();
+ if(b=='='){ // smkx enter 'keyborad_transmit' mode
+ continue;
+ }
+ }
+ }
+ }
+ else if(b=='7'){
+ b=getChar();
+ if(b=='h'){ // smam
+ // TODO
+ //System.out.println("turn on automatic magins");
+ continue;
+ }
+ else if(b=='l'){ // rmam
+ // TODO
+ //System.out.println("turn off automatic magins");
+ continue;
+ }
+ pushChar(b);
+ b='7';
+ }
+ else{
+ }
+ }
+
+ if(b=='h'){ // kh \Eh home key
+ continue;
+ }
+
+ System.out.println("unknown "+Integer.toHexString(b&0xff)+" "
+ +new Character((char)b)+", "+intarg[0]+", "+intarg[1]+", "
+ +intarg[2]+",intargi="+intargi);
+ continue;
+ }
+
+ if(b==0x07){ // bel ^G
+ bell();
+ continue;
+ }
+
+ if(b==0x09){ // ht(^I)
+ tab();
+ continue;
+ }
+
+ if(b==0x0f){ // rmacs ^O // end alternate character set (P)
+ exit_alt_charset_mode();
+ continue;
+ }
+
+ if(b==0x0e){ // smacs ^N // start alternate character set (P)
+ enter_alt_charset_mode();
+ continue;
+ }
+
+ if(b==0x0d){
+ carriage_return();
+ continue;
+ }
+
+ if(b==0x08){
+ cursor_left();
+ continue;
+ }
+
+ if(b==0x0a){ // '\n'
+ //System.out.println("x="+x+",y="+y);
+ cursor_down();
+ //check_region();
+ continue;
+ }
+
+ if(b!=0x0a){ // !'\n'
+ pushChar(b);
+ draw_text();
+ continue;
+ }
+ }
+ }
+ catch(Exception e){
+ }
+ }
+
+ private static byte[] ENTER= {(byte)0x0d};
+ private static byte[] UP= {(byte)0x1b, (byte)0x4f, (byte)0x41};
+ private static byte[] DOWN= {(byte)0x1b, (byte)0x4f, (byte)0x42};
+ private static byte[] RIGHT= {(byte)0x1b, (byte)/*0x5b*/0x4f, (byte)0x43};
+ private static byte[] LEFT= {(byte)0x1b, (byte)/*0x5b*/0x4f, (byte)0x44};
+ private static byte[] F1= {(byte)0x1b, (byte)0x4f, (byte)'P'};
+ private static byte[] F2= {(byte)0x1b, (byte)0x4f, (byte)'Q'};
+ private static byte[] F3= {(byte)0x1b, (byte)0x4f, (byte)'R'};
+ private static byte[] F4= {(byte)0x1b, (byte)0x4f, (byte)'S'};
+ private static byte[] F5= {(byte)0x1b, (byte)0x4f, (byte)'t'};
+ private static byte[] F6= {(byte)0x1b, (byte)0x4f, (byte)'u'};
+ private static byte[] F7= {(byte)0x1b, (byte)0x4f, (byte)'v'};
+ private static byte[] F8= {(byte)0x1b, (byte)0x4f, (byte)'I'};
+ private static byte[] F9= {(byte)0x1b, (byte)0x4f, (byte)'w'};
+ private static byte[] F10= {(byte)0x1b, (byte)0x4f, (byte)'x'};
+ private static byte[] tab= {(byte)0x09};
+
+ public byte[] getCodeENTER(){
+ return ENTER;
+ }
+
+ public byte[] getCodeUP(){
+ return UP;
+ }
+
+ public byte[] getCodeDOWN(){
+ return DOWN;
+ }
+
+ public byte[] getCodeRIGHT(){
+ return RIGHT;
+ }
+
+ public byte[] getCodeLEFT(){
+ return LEFT;
+ }
+
+ public byte[] getCodeF1(){
+ return F1;
+ }
+
+ public byte[] getCodeF2(){
+ return F2;
+ }
+
+ public byte[] getCodeF3(){
+ return F3;
+ }
+
+ public byte[] getCodeF4(){
+ return F4;
+ }
+
+ public byte[] getCodeF5(){
+ return F5;
+ }
+
+ public byte[] getCodeF6(){
+ return F6;
+ }
+
+ public byte[] getCodeF7(){
+ return F7;
+ }
+
+ public byte[] getCodeF8(){
+ return F8;
+ }
+
+ public byte[] getCodeF9(){
+ return F9;
+ }
+
+ public byte[] getCodeF10(){
+ return F10;
+ }
+
+ public byte[] getCodeTAB(){
+ return tab;
+ }
+}
diff --git a/src/com/jcraft/jcterm/Term.java b/src/com/jcraft/jcterm/Term.java
new file mode 100644
index 0000000..c574509
--- /dev/null
+++ b/src/com/jcraft/jcterm/Term.java
@@ -0,0 +1,80 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/* JCTerm
+ * Copyright (C) 2002,2007 ymnk, JCraft,Inc.
+ *
+ * Written by: ymnk<ymnk@jcaft.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package com.jcraft.jcterm;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public interface Term{
+
+ void start(InputStream in, OutputStream out);
+
+ int getRowCount();
+
+ int getColumnCount();
+
+ int getCharWidth();
+
+ int getCharHeight();
+
+ void setCursor(int x, int y);
+
+ void clear();
+
+ void draw_cursor();
+
+ void redraw(int x, int y, int width, int height);
+
+ //void redraw();
+ void clear_area(int x1, int y1, int x2, int y2);
+
+ void scroll_area(int x, int y, int w, int h, int dx, int dy);
+
+ void drawBytes(byte[] buf, int s, int len, int x, int y);
+
+ void drawString(String str, int x, int y);
+
+ void beep();
+
+ void setDefaultForeGround(Object foreground);
+
+ void setDefaultBackGround(Object background);
+
+ void setForeGround(Object foreground);
+
+ void setBackGround(Object background);
+
+ void setBold();
+
+ void setUnderline();
+
+ void setReverse();
+
+ void resetAllAttributes();
+
+ int getTermWidth();
+
+ int getTermHeight();
+
+ Object getColor(int index);
+}
diff --git a/src/de/mud/terminal/SoftFont.java b/src/de/mud/terminal/SoftFont.java
new file mode 100644
index 0000000..5f13f28
--- /dev/null
+++ b/src/de/mud/terminal/SoftFont.java
@@ -0,0 +1,1145 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved.
+ *
+ * Please visit http://javatelnet.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ *
+ */
+
+package de.mud.terminal;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+/**
+ * Any characters that are not available in standard java fonts may be
+ * drawn using the softfont utility. This utility class was derived from
+ * the cpi fonts used in linux console drivers.<P>
+ * <small>Font file generated by cpi2fnt</small>
+ * <P>
+ * <B>Maintainer:</B> Marcus Meissner
+ *
+ * @version $Id: SoftFont.java 499 2005-09-29 08:24:54Z leo $
+ * @author Matthias L. Jugel, Marcus Meissner
+ */
+public class SoftFont {
+ final static private char SF_BITMAP = 0;
+ final static private char SF_FILLRECT = 1;
+
+ //final static private char SF_CHAR = 0;
+ final static private char SF_WIDTH= 1;
+ final static private char SF_HEIGHT= 2;
+ final static private char SF_TYPE = 3;
+ final static private char SF_DATA = 4;
+
+ java.util.Hashtable<Integer, Integer> font;
+
+ /** softfont characterdata */
+ private static char[][] fontdata = {
+
+ {0x01,8,8,SF_BITMAP, /* 1 0x01 '^A' */
+ 0x7e, /* 01111110 */
+ 0x81, /* 10000001 */
+ 0xa5, /* 10100101 */
+ 0x81, /* 10000001 */
+ 0xbd, /* 10111101 */
+ 0x99, /* 10011001 */
+ 0x81, /* 10000001 */
+ 0x7e, /* 01111110 */
+ },{ 0x02,8,8,SF_BITMAP,/* 2 0x02 '^B' */
+ 0x7e, /* 01111110 */
+ 0xff, /* 11111111 */
+ 0xdb, /* 11011011 */
+ 0xff, /* 11111111 */
+ 0xc3, /* 11000011 */
+ 0xe7, /* 11100111 */
+ 0xff, /* 11111111 */
+ 0x7e, /* 01111110 */
+ },{ 0x03,8,8,SF_BITMAP,/* 3 0x03 '^C' */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ },{ 0x04,8,8,SF_BITMAP,/* 4 0x04 '^D' */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ },{ 0x05,8,8,SF_BITMAP,/* 5 0x05 '^E' */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xd6, /* 11010110 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ },{ 0x06,8,8,SF_BITMAP,/* 6 0x06 '^F' */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ },{ 0x2666,8,8,SF_BITMAP,/* 9830 0x2666 BLACK DIAMOND */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x07,8,8,SF_BITMAP,/* 7 0x07 '^G' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x08,8,8,SF_BITMAP,/* 8 0x08 '^H' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xe7, /* 11100111 */
+ 0xc3, /* 11000011 */
+ 0xc3, /* 11000011 */
+ 0xe7, /* 11100111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ },{ 0x09,8,8,SF_BITMAP,/* 9 0x09 '^I' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x42, /* 01000010 */
+ 0x42, /* 01000010 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ },{ 0x0a,8,8,SF_BITMAP,/* 10 0x0a '^J' */
+ 0xff, /* 11111111 */
+ 0xc3, /* 11000011 */
+ 0x99, /* 10011001 */
+ 0xbd, /* 10111101 */
+ 0xbd, /* 10111101 */
+ 0x99, /* 10011001 */
+ 0xc3, /* 11000011 */
+ 0xff, /* 11111111 */
+ },{ 0x0b,8,8,SF_BITMAP,/* 11 0x0b '^K' */
+ 0x0f, /* 00001111 */
+ 0x07, /* 00000111 */
+ 0x0f, /* 00001111 */
+ 0x7d, /* 01111101 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+ },{ 0x0c,8,8,SF_BITMAP,/* 12 0x0c '^L' */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ },{ 0x0d,8,8,SF_BITMAP,/* 13 0x0d '^M' */
+ 0x3f, /* 00111111 */
+ 0x33, /* 00110011 */
+ 0x3f, /* 00111111 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x70, /* 01110000 */
+ 0xf0, /* 11110000 */
+ 0xe0, /* 11100000 */
+ },{ 0x0e,8,8,SF_BITMAP,/* 14 0x0e '^N' */
+ 0x7f, /* 01111111 */
+ 0x63, /* 01100011 */
+ 0x7f, /* 01111111 */
+ 0x63, /* 01100011 */
+ 0x63, /* 01100011 */
+ 0x67, /* 01100111 */
+ 0xe6, /* 11100110 */
+ 0xc0, /* 11000000 */
+ },{ 0x0f,8,8,SF_BITMAP,/* 15 0x0f '^O' */
+ 0x18, /* 00011000 */
+ 0xdb, /* 11011011 */
+ 0x3c, /* 00111100 */
+ 0xe7, /* 11100111 */
+ 0xe7, /* 11100111 */
+ 0x3c, /* 00111100 */
+ 0xdb, /* 11011011 */
+ 0x18, /* 00011000 */
+ },{ 0x10,8,8,SF_BITMAP,/* 16 0x10 '^P' */
+ 0x80, /* 10000000 */
+ 0xe0, /* 11100000 */
+ 0xf8, /* 11111000 */
+ 0xfe, /* 11111110 */
+ 0xf8, /* 11111000 */
+ 0xe0, /* 11100000 */
+ 0x80, /* 10000000 */
+ 0x00, /* 00000000 */
+ },{ 0x11,8,8,SF_BITMAP,/* 17 0x11 '^Q' */
+ 0x02, /* 00000010 */
+ 0x0e, /* 00001110 */
+ 0x3e, /* 00111110 */
+ 0xfe, /* 11111110 */
+ 0x3e, /* 00111110 */
+ 0x0e, /* 00001110 */
+ 0x02, /* 00000010 */
+ 0x00, /* 00000000 */
+ },{ 0x12,8,8,SF_BITMAP,/* 18 0x12 '^R' */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ },{ 0x13,8,8,SF_BITMAP,/* 19 0x13 '^S' */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ },{ 0x14,8,8,SF_BITMAP,/* 20 0x14 '^T' */
+ 0x7f, /* 01111111 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0x7b, /* 01111011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x00, /* 00000000 */
+ },{ 0x15,8,8,SF_BITMAP,/* 21 0x15 '^U' */
+ 0x3e, /* 00111110 */
+ 0x61, /* 01100001 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x86, /* 10000110 */
+ 0x7c, /* 01111100 */
+ },{ 0x16,8,8,SF_BITMAP,/* 22 0x16 '^V' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ },{ 0x17,8,8,SF_BITMAP,/* 23 0x17 '^W' */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ },{ 0x18,8,8,SF_BITMAP,/* 24 0x18 '^X' */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ },{ 0x19,8,8,SF_BITMAP,/* 25 0x19 '^Y' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ },{ 0x1a,8,8,SF_BITMAP,/* 26 0x1a '^Z' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0xfe, /* 11111110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x1b,8,8,SF_BITMAP,/* 27 0x1b '^[' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xfe, /* 11111110 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x1c,8,8,SF_BITMAP,/* 28 0x1c '^\' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x1d,8,8,SF_BITMAP,/* 29 0x1d '^]' */
+ 0x00, /* 00000000 */
+ 0x24, /* 00100100 */
+ 0x66, /* 01100110 */
+ 0xff, /* 11111111 */
+ 0x66, /* 01100110 */
+ 0x24, /* 00100100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x1e,8,8,SF_BITMAP,/* 30 0x1e '^^' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x1f,8,8,SF_BITMAP,/* 31 0x1f '^_' */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x7f,8,8,SF_BITMAP,/* 127 0x7f '' */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ },{ 0x2591,8,8,SF_BITMAP,/* LIGHT SHADE */
+ 0x22, /* 00100010 */
+ 0x88, /* 10001000 */
+ 0x22, /* 00100010 */
+ 0x88, /* 10001000 */
+ 0x22, /* 00100010 */
+ 0x88, /* 10001000 */
+ 0x22, /* 00100010 */
+ 0x88, /* 10001000 */
+ },{ 0x2592,8,8,SF_BITMAP,/* MEDIUM SHADE */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ },{ 0x2593,8,8,SF_BITMAP,/* DARK SHADE */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ },{ 0x221a,8,8,SF_BITMAP,/* SQUARE ROOT */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x2320,8,8,SF_FILLRECT,/* UPPER INTERVAL*/
+ 0x4031,
+ 0x3127,
+ 0x6122,
+ /* 00001110 */
+ /* 00011011 */
+ /* 00011011 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2321,8,8,SF_FILLRECT,/* BOTTOM HALF INTEGRAL */
+ 0x3027,
+ 0x0522,
+ 0x1731,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 11011000 */
+ /* 11011000 */
+ /* 01110000 */
+ },{ 0x25a0,8,8,SF_FILLRECT,/* BLACK SQUARE */
+ 0x2244,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00111100 */
+ /* 00111100 */
+ /* 00111100 */
+ /* 00111100 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2502,8,8,SF_FILLRECT,/*BOX DRAWINGS LIGHT VERTICAL*/
+ 0x3028,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2524,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+ 0x3028,
+ 0x0431,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 11111000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2561,8,8,SF_FILLRECT,/*BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE*/
+ 0x3028,
+ 0x0231,
+ 0x0431,
+ /* 00011000 */
+ /* 00011000 */
+ /* 11111000 */
+ /* 00011000 */
+ /* 11111000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2562,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE */
+ 0x2028,
+ 0x5028,
+ 0x0421,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 11110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2556,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE */
+ 0x0471,
+ 0x2523,
+ 0x5523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2555,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE */
+ 0x3226,
+ 0x0231,
+ 0x0431,
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111000 */
+ /* 00011000 */
+ /* 11111000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2563,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND LEFT*/
+ 0x2022,
+ 0x0221,
+ 0x0421,
+ 0x2424,
+ 0x5028,
+ /* 00110110 */
+ /* 00110110 */
+ /* 11110110 */
+ /* 00000110 */
+ /* 11110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2551,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL */
+ 0x2028,
+ 0x5028,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2557,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND LEFT */
+ 0x0271,
+ 0x5325,
+ 0x0441,
+ 0x2523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111110 */
+ /* 00000110 */
+ /* 11110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x255d,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND LEFT */
+ 0x2022,
+ 0x0241,
+ 0x5025,
+ 0x0451,
+ /* 00110110 */
+ /* 00110110 */
+ /* 11110110 */
+ /* 00000110 */
+ /* 11111110 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x255c,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND LEFT SINGLE */
+ 0x2024,
+ 0x5024,
+ 0x0471,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 11111110 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x255b,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND LEFT DOUBLE */
+ 0x3025,
+ 0x0231,
+ 0x0431,
+ /* 00011000 */
+ /* 00011000 */
+ /* 11111000 */
+ /* 00011000 */
+ /* 11111000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2510,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND LEFT */
+ 0x0451,
+ 0x3523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2514,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND RIGHT */
+ 0x3025,
+ 0x5431,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2534,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+ 0x3024,
+ 0x0481,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x252c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+ 0x0481,
+ 0x3523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x251c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+ 0x3028,
+ 0x5431,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011111 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2500,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT HORIZONTAL */
+ 0x0481,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2594,8,8,SF_FILLRECT,/* UPPER 1/8 (1st scanline) */
+ 0x0081,
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x25ac,8,8,SF_FILLRECT,/* LOWER 1/8 (7nd scanline) */
+ 0x0781,
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x253c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+ 0x3028,
+ 0x0481,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 11111111 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x255e,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE */
+ 0x3028,
+ 0x5231,
+ 0x5431,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011111 */
+ /* 00011000 */
+ /* 00011111 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x255f,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE */
+ 0x2028,
+ 0x5028,
+ 0x7411,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110111 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x255a,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND RIGHT */
+ 0x2025,
+ 0x5023,
+ 0x7211,
+ 0x4441,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110111 */
+ /* 00110000 */
+ /* 00111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2554,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND RIGHT */
+ 0x2261,
+ 0x2325,
+ 0x5424,
+ 0x7411,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00111111 */
+ /* 00110000 */
+ /* 00110111 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2569,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND HORIZONTAL */
+ 0x2022,
+ 0x0241,
+ 0x5022,
+ 0x5231,
+ 0x0481,
+ /* 00110110 */
+ /* 00110110 */
+ /* 11110111 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2566,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */
+ 0x0281,
+ 0x0441,
+ 0x2523,
+ 0x5431,
+ 0x5523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 11110111 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2560,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */
+ 0x2028,
+ 0x5022,
+ 0x5231,
+ 0x5431,
+ 0x5623,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110111 */
+ /* 00110000 */
+ /* 00110111 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2550,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE HORIZONTAL */
+ 0x0281,
+ 0x0481,
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x256c,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */
+ 0x2022,
+ 0x0241,
+ 0x5022,
+ 0x5231,
+ 0x0441,
+ 0x2523,
+ 0x5431,
+ 0x5523,
+ /* 00110110 */
+ /* 00110110 */
+ /* 11110111 */
+ /* 00000000 */
+ /* 11110111 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2567,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE */
+ 0x3022,
+ 0x0281,
+ 0x0481,
+ /* 00011000 */
+ /* 00011000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2568,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE */
+ 0x2024,
+ 0x5024,
+ 0x0481,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2564,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE */
+ 0x0281,
+ 0x0481,
+ 0x3523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2565,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE */
+ 0x0481,
+ 0x2523,
+ 0x5523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x2559,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE */
+ 0x2024,
+ 0x5024,
+ 0x2461,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2558,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE */
+ 0x3025,
+ 0x5231,
+ 0x5431,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011111 */
+ /* 00011000 */
+ /* 00011111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2552,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE */
+ 0x3226,
+ 0x5231,
+ 0x5431,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00011111 */
+ /* 00011000 */
+ /* 00011111 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2553,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE */
+ 0x2461,
+ 0x2523,
+ 0x5523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00111111 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x256b,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE */
+ 0x2028,
+ 0x5028,
+ 0x0481,
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 11111111 */
+ /* 00110110 */
+ /* 00110110 */
+ /* 00110110 */
+ },{ 0x256a,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE */
+ 0x3028,
+ 0x0281,
+ 0x0481,
+ /* 00011000 */
+ /* 00011000 */
+ /* 11111111 */
+ /* 00011000 */
+ /* 11111111 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2518,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND LEFT */
+ 0x3025,
+ 0x0431,
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 11111000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x250c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND RIGHT */
+ 0x3451,
+ 0x3523,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00011111 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00011000 */
+ },{ 0x2588,8,8,SF_FILLRECT,/* FULL BLOCK */
+ 0x0088,
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ },{ 0x2584,8,8,SF_FILLRECT,/* LOWER HALF BLOCK */
+ 0x0484,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ },{ 0x258c,8,8,SF_FILLRECT,/* LEFT HALF BLOCK */
+ 0x0048,
+ /* 11110000 */
+ /* 11110000 */
+ /* 11110000 */
+ /* 11110000 */
+ /* 11110000 */
+ /* 11110000 */
+ /* 11110000 */
+ /* 11110000 */
+ },{ 0x2590,8,8,SF_FILLRECT,/* RIGHT HALF BLOCK */
+ 0x4048,
+ /* 00001111 */
+ /* 00001111 */
+ /* 00001111 */
+ /* 00001111 */
+ /* 00001111 */
+ /* 00001111 */
+ /* 00001111 */
+ /* 00001111 */
+ },{ 0x2580,8,8,SF_FILLRECT,/* UPPER HALF BLOCK */
+ 0x0084,
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2261,8,8,SF_FILLRECT,/* EQUIVALENT SIGN */
+ 0x2081,
+ 0x4081,
+ 0x6081,
+ /* 00000000 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ /* 11111111 */
+ /* 00000000 */
+ },{ 0x221e,8,8,SF_BITMAP,/* INFINITY */
+ 0x00,
+ 0x00,
+ 0x7e,
+ 0xdb,
+ 0xdb,
+ 0x7e,
+ 0x00,
+ 0x00,
+ /* 00000000 */
+ /* 00000000 */
+ /* 01111110 */
+ /* 11011011 */
+ /* 11011011 */
+ /* 01111110 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x207f,8,8,SF_FILLRECT,/* small superscript n */
+ 0x1041,
+ 0x1124,
+ 0x4124,
+ /* 01111000 */
+ /* 01101100 */
+ /* 01101100 */
+ /* 01101100 */
+ /* 01101100 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x00b2,8,8,SF_BITMAP,/* small superscript 2 */
+ 0x70, /* 01110000 */
+ 0x1c, /* 00011100 */
+ 0x38, /* 00111000 */
+ 0x60, /* 01100000 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ },{ 0x2219,8,8,SF_FILLRECT,/* BULLET OPERATOR */
+ 0x3322,
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00011000 */
+ /* 00011000 */
+ /* 00000000 */
+ /* 00000000 */
+ /* 00000000 */
+ },{ 0x2191,8,8,SF_BITMAP,/* UP ARROW */
+ 0x08, /* 00001000 */
+ 0x1c, /* 00011100 */
+ 0x3e, /* 00111110 */
+ 0x7f, /* 01111111 */
+ 0x1c, /* 00011100 */
+ 0x1c, /* 00011100 */
+ 0x1c, /* 00011100 */
+ 0x1c, /* 00011100 */
+ },{ 0x2193,8,8,SF_BITMAP,/* DOWN ARROW */
+ 0x1c, /* 00011100 */
+ 0x1c, /* 00011100 */
+ 0x1c, /* 00011100 */
+ 0x1c, /* 00011100 */
+ 0x7f, /* 01111111 */
+ 0x3e, /* 00111110 */
+ 0x1c, /* 00011100 */
+ 0x08, /* 00001000 */
+ },{ 0x25ba,8,8,SF_BITMAP,/* RIGHT ARROW (TRIANGLE ONLY) */
+ 0x00, /* 00000000 */
+ 0x40, /* 01000000 */
+ 0x60, /* 01100000 */
+ 0x7c, /* 01111100 */
+ 0x70, /* 01110000 */
+ 0x60, /* 01100000 */
+ 0x40, /* 01000000 */
+ 0x00, /* 00000000 */
+ },{ 0x25c4,8,8,SF_BITMAP,/* LEFT ARROW (TRIANGLE ONLY) */
+ 0x00, /* 00000000 */
+ 0x02, /* 00000010 */
+ 0x06, /* 00000110 */
+ 0x3e, /* 00111110 */
+ 0x0e, /* 00001110 */
+ 0x06, /* 00000110 */
+ 0x02, /* 00000010 */
+ 0x00, /* 00000000 */
+ }};
+
+ public SoftFont() {
+ font = new java.util.Hashtable<Integer, Integer>();
+ for (int i=0;i<fontdata.length;i++)
+ font.put(new Integer(fontdata[i][0]),new Integer(i));
+ }
+
+ public boolean inSoftFont(char c) {
+ boolean insoftfont;
+
+ insoftfont = (null!=font.get(new Integer(c)));
+ if (!insoftfont && (int)c>=0x100) {
+ System.out.println("Character "+((int)c)+" not in softfont");
+ }
+ return insoftfont;
+ }
+
+ public void drawChar(Canvas g, Paint p, char c,int x,int y,int cw,int ch) {
+ double dw,dh;
+ Object Ientry;
+ int w,h,entry,i,fontwidth,fontheight;
+
+ Ientry = font.get(new Integer(c));
+ if (Ientry == null)
+ return;
+ entry = ((Integer)Ientry).intValue();
+ fontwidth = fontdata[entry][SF_WIDTH];
+ fontheight = fontdata[entry][SF_HEIGHT];
+
+ dw = cw*1.0/fontwidth;
+ dh = ch*1.0/fontheight;
+
+ switch (fontdata[entry][SF_TYPE]) {
+ case SF_BITMAP:
+ for (h=0;h<fontheight;h++) {
+ for (w=0;w<fontwidth;w++) {
+ //FIXME: 8 bit max currently...
+ if (0!=(fontdata[entry][h+SF_DATA] & (1<<(7-w)))) {
+ g.drawRect(
+ x+(int)(w*dw),
+ y+(int)(h*dh),
+ ((int)((w+1)*dw))-(int)(w*dw),
+ ((int)((h+1)*dh))-(int)(h*dh),
+ p
+ );
+ }
+ }
+ }
+ break;
+ case SF_FILLRECT:
+ i=SF_DATA;
+ while (i<fontdata[entry].length) {
+ int xw,xh;
+
+ w=(fontdata[entry][i]&0xF000)>>12;
+ h=(fontdata[entry][i]&0x0F00)>>8;
+ xw = (fontdata[entry][i]&0x00F0)>>4;
+ xh = (fontdata[entry][i]&0x000F);
+ g.drawRect(
+ x+(int)(w*dw),
+ y+(int)(h*dh),
+ ((int)((w+xw)*dw))-(int)(w*dw),
+ ((int)((h+xh)*dh))-(int)(h*dh),
+ p
+ );
+ i++;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/src/de/mud/terminal/VDUBuffer.java b/src/de/mud/terminal/VDUBuffer.java
new file mode 100644
index 0000000..7f203e6
--- /dev/null
+++ b/src/de/mud/terminal/VDUBuffer.java
@@ -0,0 +1,791 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved.
+ *
+ * Please visit http://javatelnet.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ *
+ */
+
+package de.mud.terminal;
+
+/**
+ * Implementation of a Video Display Unit (VDU) buffer. This class contains
+ * all methods to manipulate the buffer that stores characters and their
+ * attributes as well as the regions displayed.
+ *
+ * @author Matthias L. Jugel, Marcus Mei�ner
+ * @version $Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $
+ */
+public class VDUBuffer {
+
+ /** The current version id tag */
+ public final static String ID = "$Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $";
+
+ /** Enable debug messages. */
+ public final static int debug = 0;
+
+ public int height, width; /* rows and columns */
+ public boolean[] update; /* contains the lines that need update */
+ public char[][] charArray; /* contains the characters */
+ public int[][] charAttributes; /* contains character attrs */
+ public int bufSize;
+ public int maxBufSize; /* buffer sizes */
+ public int screenBase; /* the actual screen start */
+ public int windowBase; /* where the start displaying */
+ public int scrollMarker; /* marks the last line inserted */
+
+ private int topMargin; /* top scroll margin */
+ private int bottomMargin; /* bottom scroll margin */
+
+ // cursor variables
+ protected boolean showcursor = true;
+ protected int cursorX, cursorY;
+
+ /** Scroll up when inserting a line. */
+ public final static boolean SCROLL_UP = false;
+ /** Scroll down when inserting a line. */
+ public final static boolean SCROLL_DOWN = true;
+
+ /** Make character normal. */
+ public final static int NORMAL = 0x00;
+ /** Make character bold. */
+ public final static int BOLD = 0x01;
+ /** Underline character. */
+ public final static int UNDERLINE = 0x02;
+ /** Invert character. */
+ public final static int INVERT = 0x04;
+ /** Lower intensity character. */
+ public final static int LOW = 0x08;
+ /** Invisible character. */
+ public final static int INVISIBLE = 0x10;
+
+ /** how much to left shift the foreground color */
+ public final static int COLOR_FG_SHIFT = 5;
+ /** how much to left shift the background color */
+ public final static int COLOR_BG_SHIFT = 9;
+ /** color mask */
+ public final static int COLOR = 0x1fe0;
+ /** foreground color mask */
+ public final static int COLOR_FG = 0x1e0;
+ /** background color mask */
+ public final static int COLOR_BG = 0x1e00;
+
+ /**
+ * Create a new video display buffer with the passed width and height in
+ * characters.
+ * @param width the length of the character lines
+ * @param height the amount of lines on the screen
+ */
+ public VDUBuffer(int width, int height) {
+ // set the display screen size
+ setScreenSize(width, height, false);
+ }
+
+ /**
+ * Create a standard video display buffer with 80 columns and 24 lines.
+ */
+ public VDUBuffer() {
+ this(80, 24);
+ }
+
+ /**
+ * Put a character on the screen with normal font and outline.
+ * The character previously on that position will be overwritten.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param ch the character to show on the screen
+ * @see #insertChar
+ * @see #deleteChar
+ * @see #redraw
+ */
+ public void putChar(int c, int l, char ch) {
+ putChar(c, l, ch, NORMAL);
+ }
+
+ /**
+ * Put a character on the screen with specific font and outline.
+ * The character previously on that position will be overwritten.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param ch the character to show on the screen
+ * @param attributes the character attributes
+ * @see #BOLD
+ * @see #UNDERLINE
+ * @see #INVERT
+ * @see #INVISIBLE
+ * @see #NORMAL
+ * @see #LOW
+ * @see #insertChar
+ * @see #deleteChar
+ * @see #redraw
+ */
+
+ public void putChar(int c, int l, char ch, int attributes) {
+ c = checkBounds(c, 0, width - 1);
+ l = checkBounds(l, 0, height - 1);
+ charArray[screenBase + l][c] = ch;
+ charAttributes[screenBase + l][c] = attributes;
+ markLine(l, 1);
+ }
+
+ /**
+ * Get the character at the specified position.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @see #putChar
+ */
+ public char getChar(int c, int l) {
+ c = checkBounds(c, 0, width - 1);
+ l = checkBounds(l, 0, height - 1);
+ return charArray[screenBase + l][c];
+ }
+
+ /**
+ * Get the attributes for the specified position.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @see #putChar
+ */
+ public int getAttributes(int c, int l) {
+ c = checkBounds(c, 0, width - 1);
+ l = checkBounds(l, 0, height - 1);
+ return charAttributes[screenBase + l][c];
+ }
+
+ /**
+ * Insert a character at a specific position on the screen.
+ * All character right to from this position will be moved one to the right.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param ch the character to insert
+ * @param attributes the character attributes
+ * @see #BOLD
+ * @see #UNDERLINE
+ * @see #INVERT
+ * @see #INVISIBLE
+ * @see #NORMAL
+ * @see #LOW
+ * @see #putChar
+ * @see #deleteChar
+ * @see #redraw
+ */
+ public void insertChar(int c, int l, char ch, int attributes) {
+ c = checkBounds(c, 0, width - 1);
+ l = checkBounds(l, 0, height - 1);
+ System.arraycopy(charArray[screenBase + l], c,
+ charArray[screenBase + l], c + 1, width - c - 1);
+ System.arraycopy(charAttributes[screenBase + l], c,
+ charAttributes[screenBase + l], c + 1, width - c - 1);
+ putChar(c, l, ch, attributes);
+ }
+
+ /**
+ * Delete a character at a given position on the screen.
+ * All characters right to the position will be moved one to the left.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @see #putChar
+ * @see #insertChar
+ * @see #redraw
+ */
+ public void deleteChar(int c, int l) {
+ c = checkBounds(c, 0, width - 1);
+ l = checkBounds(l, 0, height - 1);
+ if (c < width - 1) {
+ System.arraycopy(charArray[screenBase + l], c + 1,
+ charArray[screenBase + l], c, width - c - 1);
+ System.arraycopy(charAttributes[screenBase + l], c + 1,
+ charAttributes[screenBase + l], c, width - c - 1);
+ }
+ putChar(width - 1, l, (char) 0);
+ }
+
+ /**
+ * Put a String at a specific position. Any characters previously on that
+ * position will be overwritten. You need to call redraw() for screen update.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param s the string to be shown on the screen
+ * @see #BOLD
+ * @see #UNDERLINE
+ * @see #INVERT
+ * @see #INVISIBLE
+ * @see #NORMAL
+ * @see #LOW
+ * @see #putChar
+ * @see #insertLine
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void putString(int c, int l, String s) {
+ putString(c, l, s, NORMAL);
+ }
+
+ /**
+ * Put a String at a specific position giving all characters the same
+ * attributes. Any characters previously on that position will be
+ * overwritten. You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param s the string to be shown on the screen
+ * @param attributes character attributes
+ * @see #BOLD
+ * @see #UNDERLINE
+ * @see #INVERT
+ * @see #INVISIBLE
+ * @see #NORMAL
+ * @see #LOW
+ * @see #putChar
+ * @see #insertLine
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void putString(int c, int l, String s, int attributes) {
+ for (int i = 0; i < s.length() && c + i < width; i++)
+ putChar(c + i, l, s.charAt(i), attributes);
+ }
+
+ /**
+ * Insert a blank line at a specific position.
+ * The current line and all previous lines are scrolled one line up. The
+ * top line is lost. You need to call redraw() to update the screen.
+ * @param l the y-coordinate to insert the line
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void insertLine(int l) {
+ insertLine(l, 1, SCROLL_UP);
+ }
+
+ /**
+ * Insert blank lines at a specific position.
+ * You need to call redraw() to update the screen
+ * @param l the y-coordinate to insert the line
+ * @param n amount of lines to be inserted
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void insertLine(int l, int n) {
+ insertLine(l, n, SCROLL_UP);
+ }
+
+ /**
+ * Insert a blank line at a specific position. Scroll text according to
+ * the argument.
+ * You need to call redraw() to update the screen
+ * @param l the y-coordinate to insert the line
+ * @param scrollDown scroll down
+ * @see #deleteLine
+ * @see #SCROLL_UP
+ * @see #SCROLL_DOWN
+ * @see #redraw
+ */
+ public void insertLine(int l, boolean scrollDown) {
+ insertLine(l, 1, scrollDown);
+ }
+
+ /**
+ * Insert blank lines at a specific position.
+ * The current line and all previous lines are scrolled one line up. The
+ * top line is lost. You need to call redraw() to update the screen.
+ * @param l the y-coordinate to insert the line
+ * @param n number of lines to be inserted
+ * @param scrollDown scroll down
+ * @see #deleteLine
+ * @see #SCROLL_UP
+ * @see #SCROLL_DOWN
+ * @see #redraw
+ */
+ public synchronized void insertLine(int l, int n, boolean scrollDown) {
+ l = checkBounds(l, 0, height - 1);
+
+ char cbuf[][] = null;
+ int abuf[][] = null;
+ int offset = 0;
+ int oldBase = screenBase;
+
+ if (l > bottomMargin) /* We do not scroll below bottom margin (below the scrolling region). */
+ return;
+ int top = (l < topMargin ?
+ 0 : (l > bottomMargin ?
+ (bottomMargin + 1 < height ?
+ bottomMargin + 1 : height - 1) : topMargin));
+ int bottom = (l > bottomMargin ?
+ height - 1 : (l < topMargin ?
+ (topMargin > 0 ?
+ topMargin - 1 : 0) : bottomMargin));
+
+ // System.out.println("l is "+l+", top is "+top+", bottom is "+bottom+", bottomargin is "+bottomMargin+", topMargin is "+topMargin);
+
+ if (scrollDown) {
+ if (n > (bottom - top)) n = (bottom - top);
+ cbuf = new char[bottom - l - (n - 1)][width];
+ abuf = new int[bottom - l - (n - 1)][width];
+
+ System.arraycopy(charArray, oldBase + l, cbuf, 0, bottom - l - (n - 1));
+ System.arraycopy(charAttributes, oldBase + l,
+ abuf, 0, bottom - l - (n - 1));
+ System.arraycopy(cbuf, 0, charArray, oldBase + l + n,
+ bottom - l - (n - 1));
+ System.arraycopy(abuf, 0, charAttributes, oldBase + l + n,
+ bottom - l - (n - 1));
+ cbuf = charArray;
+ abuf = charAttributes;
+ } else {
+ try {
+ if (n > (bottom - top) + 1) n = (bottom - top) + 1;
+ if (bufSize < maxBufSize) {
+ if (bufSize + n > maxBufSize) {
+ offset = n - (maxBufSize - bufSize);
+ scrollMarker += offset;
+ bufSize = maxBufSize;
+ screenBase = maxBufSize - height - 1;
+ windowBase = screenBase;
+ } else {
+ scrollMarker += n;
+ screenBase += n;
+ windowBase += n;
+ bufSize += n;
+ }
+
+ cbuf = new char[bufSize][width];
+ abuf = new int[bufSize][width];
+ } else {
+ offset = n;
+ cbuf = charArray;
+ abuf = charAttributes;
+ }
+ // copy anything from the top of the buffer (+offset) to the new top
+ // up to the screenBase.
+ if (oldBase > 0) {
+ System.arraycopy(charArray, offset,
+ cbuf, 0,
+ oldBase - offset);
+ System.arraycopy(charAttributes, offset,
+ abuf, 0,
+ oldBase - offset);
+ }
+ // copy anything from the top of the screen (screenBase) up to the
+ // topMargin to the new screen
+ if (top > 0) {
+ System.arraycopy(charArray, oldBase,
+ cbuf, screenBase,
+ top);
+ System.arraycopy(charAttributes, oldBase,
+ abuf, screenBase,
+ top);
+ }
+ // copy anything from the topMargin up to the amount of lines inserted
+ // to the gap left over between scrollback buffer and screenBase
+ if (oldBase > 0) {
+ System.arraycopy(charArray, oldBase + top,
+ cbuf, oldBase - offset,
+ n);
+ System.arraycopy(charAttributes, oldBase + top,
+ abuf, oldBase - offset,
+ n);
+ }
+ // copy anything from topMargin + n up to the line linserted to the
+ // topMargin
+ System.arraycopy(charArray, oldBase + top + n,
+ cbuf, screenBase + top,
+ l - top - (n - 1));
+ System.arraycopy(charAttributes, oldBase + top + n,
+ abuf, screenBase + top,
+ l - top - (n - 1));
+ //
+ // copy the all lines next to the inserted to the new buffer
+ if (l < height - 1) {
+ System.arraycopy(charArray, oldBase + l + 1,
+ cbuf, screenBase + l + 1,
+ (height - 1) - l);
+ System.arraycopy(charAttributes, oldBase + l + 1,
+ abuf, screenBase + l + 1,
+ (height - 1) - l);
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // this should not happen anymore, but I will leave the code
+ // here in case something happens anyway. That code above is
+ // so complex I always have a hard time understanding what
+ // I did, even though there are comments
+ System.err.println("*** Error while scrolling up:");
+ System.err.println("--- BEGIN STACK TRACE ---");
+ e.printStackTrace();
+ System.err.println("--- END STACK TRACE ---");
+ System.err.println("bufSize=" + bufSize + ", maxBufSize=" + maxBufSize);
+ System.err.println("top=" + top + ", bottom=" + bottom);
+ System.err.println("n=" + n + ", l=" + l);
+ System.err.println("screenBase=" + screenBase + ", windowBase=" + windowBase);
+ System.err.println("oldBase=" + oldBase);
+ System.err.println("size.width=" + width + ", size.height=" + height);
+ System.err.println("abuf.length=" + abuf.length + ", cbuf.length=" + cbuf.length);
+ System.err.println("*** done dumping debug information");
+ }
+ }
+
+ // this is a little helper to mark the scrolling
+ scrollMarker -= n;
+
+
+ for (int i = 0; i < n; i++) {
+ cbuf[(screenBase + l) + (scrollDown ? i : -i)] = new char[width];
+ abuf[(screenBase + l) + (scrollDown ? i : -i)] = new int[width];
+ }
+
+ charArray = cbuf;
+ charAttributes = abuf;
+
+ if (scrollDown)
+ markLine(l, bottom - l + 1);
+ else
+ markLine(top, l - top + 1);
+
+ display.updateScrollBar();
+ }
+
+ /**
+ * Delete a line at a specific position. Subsequent lines will be scrolled
+ * up to fill the space and a blank line is inserted at the end of the
+ * screen.
+ * @param l the y-coordinate to insert the line
+ * @see #deleteLine
+ */
+ public void deleteLine(int l) {
+ l = checkBounds(l, 0, height - 1);
+
+ int bottom = (l > bottomMargin ? height - 1:
+ (l < topMargin?topMargin:bottomMargin + 1));
+ System.arraycopy(charArray, screenBase + l + 1,
+ charArray, screenBase + l, bottom - l - 1);
+ System.arraycopy(charAttributes, screenBase + l + 1,
+ charAttributes, screenBase + l, bottom - l - 1);
+ charArray[screenBase + bottom - 1] = new char[width];
+ charAttributes[screenBase + bottom - 1] = new int[width];
+ markLine(l, bottom - l);
+ }
+
+ /**
+ * Delete a rectangular portion of the screen.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (row)
+ * @param w with of the area in characters
+ * @param h height of the area in characters
+ * @param curAttr attribute to fill
+ * @see #deleteChar
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void deleteArea(int c, int l, int w, int h, int curAttr) {
+ c = checkBounds(c, 0, width - 1);
+ l = checkBounds(l, 0, height - 1);
+
+ char cbuf[] = new char[w];
+ int abuf[] = new int[w];
+
+ for (int i = 0; i < w; i++) abuf[i] = curAttr;
+ for (int i = 0; i < h && l + i < height; i++) {
+ System.arraycopy(cbuf, 0, charArray[screenBase + l + i], c, w);
+ System.arraycopy(abuf, 0, charAttributes[screenBase + l + i], c, w);
+ }
+ markLine(l, h);
+ }
+
+ /**
+ * Delete a rectangular portion of the screen.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (row)
+ * @param w with of the area in characters
+ * @param h height of the area in characters
+ * @see #deleteChar
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void deleteArea(int c, int l, int w, int h) {
+ c = checkBounds(c, 0, width - 1);
+ l = checkBounds(l, 0, height - 1);
+
+ char cbuf[] = new char[w];
+ int abuf[] = new int[w];
+
+ for (int i = 0; i < h && l + i < height; i++) {
+ System.arraycopy(cbuf, 0, charArray[screenBase + l + i], c, w);
+ System.arraycopy(abuf, 0, charAttributes[screenBase + l + i], c, w);
+ }
+ markLine(l, h);
+ }
+
+ /**
+ * Sets whether the cursor is visible or not.
+ * @param doshow
+ */
+ public void showCursor(boolean doshow) {
+ if (doshow != showcursor)
+ markLine(cursorY, 1);
+ showcursor = doshow;
+ }
+
+ /**
+ * Puts the cursor at the specified position.
+ * @param c column
+ * @param l line
+ */
+ public void setCursorPosition(int c, int l) {
+ cursorX = checkBounds(c, 0, width - 1);
+ cursorY = checkBounds(l, 0, height - 1);
+ markLine(cursorY, 1);
+ }
+
+ /**
+ * Get the current column of the cursor position.
+ */
+ public int getCursorColumn() {
+ return cursorX;
+ }
+
+ /**
+ * Get the current line of the cursor position.
+ */
+ public int getCursorRow() {
+ return cursorY;
+ }
+
+ /**
+ * Set the current window base. This allows to view the scrollback buffer.
+ * @param line the line where the screen window starts
+ * @see #setBufferSize
+ * @see #getBufferSize
+ */
+ public void setWindowBase(int line) {
+ if (line > screenBase)
+ line = screenBase;
+ else if (line < 0) line = 0;
+ windowBase = line;
+ update[0] = true;
+ redraw();
+ }
+
+ /**
+ * Get the current window base.
+ * @see #setWindowBase
+ */
+ public int getWindowBase() {
+ return windowBase;
+ }
+
+ /**
+ * Set the top scroll margin for the screen. If the current bottom margin
+ * is smaller it will become the top margin and the line will become the
+ * bottom margin.
+ * @param l line that is the margin
+ */
+ public void setTopMargin(int l) {
+ if (l > bottomMargin) {
+ topMargin = bottomMargin;
+ bottomMargin = l;
+ } else
+ topMargin = l;
+ if (topMargin < 0) topMargin = 0;
+ if (bottomMargin > height - 1) bottomMargin = height - 1;
+ }
+
+ /**
+ * Get the top scroll margin.
+ */
+ public int getTopMargin() {
+ return topMargin;
+ }
+
+ /**
+ * Set the bottom scroll margin for the screen. If the current top margin
+ * is bigger it will become the bottom margin and the line will become the
+ * top margin.
+ * @param l line that is the margin
+ */
+ public void setBottomMargin(int l) {
+ if (l < topMargin) {
+ bottomMargin = topMargin;
+ topMargin = l;
+ } else
+ bottomMargin = l;
+ if (topMargin < 0) topMargin = 0;
+ if (bottomMargin > height - 1) bottomMargin = height - 1;
+ }
+
+ /**
+ * Get the bottom scroll margin.
+ */
+ public int getBottomMargin() {
+ return bottomMargin;
+ }
+
+ /**
+ * Set scrollback buffer size.
+ * @param amount new size of the buffer
+ */
+ public void setBufferSize(int amount) {
+ if (amount < height) amount = height;
+ if (amount < maxBufSize) {
+ char cbuf[][] = new char[amount][width];
+ int abuf[][] = new int[amount][width];
+ int copyStart = bufSize - amount < 0 ? 0 : bufSize - amount;
+ int copyCount = bufSize - amount < 0 ? bufSize : amount;
+ if (charArray != null)
+ System.arraycopy(charArray, copyStart, cbuf, 0, copyCount);
+ if (charAttributes != null)
+ System.arraycopy(charAttributes, copyStart, abuf, 0, copyCount);
+ charArray = cbuf;
+ charAttributes = abuf;
+ bufSize = copyCount;
+ screenBase = bufSize - height;
+ windowBase = screenBase;
+ }
+ maxBufSize = amount;
+
+ update[0] = true;
+ redraw();
+ }
+
+ /**
+ * Retrieve current scrollback buffer size.
+ * @see #setBufferSize
+ */
+ public int getBufferSize() {
+ return bufSize;
+ }
+
+ /**
+ * Retrieve maximum buffer Size.
+ * @see #getBufferSize
+ */
+ public int getMaxBufferSize() {
+ return maxBufSize;
+ }
+
+ /**
+ * Change the size of the screen. This will include adjustment of the
+ * scrollback buffer.
+ * @param w of the screen
+ * @param h of the screen
+ */
+ public void setScreenSize(int w, int h, boolean broadcast) {
+ char cbuf[][];
+ int abuf[][];
+ int bsize = bufSize;
+
+ if (w < 1 || h < 1) return;
+
+ if (debug > 0)
+ System.err.println("VDU: screen size [" + w + "," + h + "]");
+
+ if (h > maxBufSize)
+ maxBufSize = h;
+
+ if (h > bufSize) {
+ bufSize = h;
+ screenBase = 0;
+ windowBase = 0;
+ }
+
+ if (windowBase + h >= bufSize)
+ windowBase = bufSize - h;
+
+ if (screenBase + h >= bufSize)
+ screenBase = bufSize - h;
+
+
+ cbuf = new char[bufSize][w];
+ abuf = new int[bufSize][w];
+
+ if (charArray != null && charAttributes != null) {
+ for (int i = 0; i < bsize && i < bufSize; i++) {
+ System.arraycopy(charArray[i], 0, cbuf[i], 0,
+ w < width ? w : width);
+ System.arraycopy(charAttributes[i], 0, abuf[i], 0,
+ w < width ? w : width);
+ }
+ }
+
+ charArray = cbuf;
+ charAttributes = abuf;
+ width = w;
+ height = h;
+ topMargin = 0;
+ bottomMargin = h - 1;
+ update = new boolean[h + 1];
+ update[0] = true;
+ /* FIXME: ???
+ if(resizeStrategy == RESIZE_FONT)
+ setBounds(getBounds());
+ */
+ }
+
+ /**
+ * Get amount of rows on the screen.
+ */
+ public int getRows() {
+ return height;
+ }
+
+ /**
+ * Get amount of columns on the screen.
+ */
+ public int getColumns() {
+ return width;
+ }
+
+ /**
+ * Mark lines to be updated with redraw().
+ * @param l starting line
+ * @param n amount of lines to be updated
+ * @see #redraw
+ */
+ public void markLine(int l, int n) {
+ l = checkBounds(l, 0, height - 1);
+ for (int i = 0; (i < n) && (l + i < height); i++)
+ update[l + i + 1] = true;
+ }
+
+ private int checkBounds(int value, int lower, int upper) {
+ if (value < lower) return lower;
+ if (value > upper) return upper;
+ return value;
+ }
+
+ /** a generic display that should redraw on demand */
+ protected VDUDisplay display;
+
+ public void setDisplay(VDUDisplay display) {
+ this.display = display;
+ }
+
+ /**
+ * Trigger a redraw on the display.
+ */
+ protected void redraw() {
+ if (display != null)
+ display.redraw();
+ }
+}
diff --git a/src/de/mud/terminal/VDUDisplay.java b/src/de/mud/terminal/VDUDisplay.java
new file mode 100644
index 0000000..4323465
--- /dev/null
+++ b/src/de/mud/terminal/VDUDisplay.java
@@ -0,0 +1,37 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved.
+ *
+ * Please visit http://javatelnet.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ *
+ */
+
+package de.mud.terminal;
+
+/**
+ * Generic display
+ */
+public interface VDUDisplay {
+ public void redraw();
+ public void updateScrollBar();
+
+ public void setVDUBuffer(VDUBuffer buffer);
+ public VDUBuffer getVDUBuffer();
+}
diff --git a/src/de/mud/terminal/VDUInput.java b/src/de/mud/terminal/VDUInput.java
new file mode 100644
index 0000000..79a8bb7
--- /dev/null
+++ b/src/de/mud/terminal/VDUInput.java
@@ -0,0 +1,89 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved.
+ *
+ * Please visit http://javatelnet.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ *
+ */
+package de.mud.terminal;
+
+import java.util.Properties;
+
+/**
+ * An interface for a terminal that accepts input from keyboard and mouse.
+ *
+ * @author Matthias L. Jugel, Marcus Mei�ner
+ * @version $Id: VDUInput.java 499 2005-09-29 08:24:54Z leo $
+ */
+public interface VDUInput {
+
+ public final static int KEY_CONTROL = 0x01;
+ public final static int KEY_SHIFT = 0x02;
+ public final static int KEY_ALT = 0x04;
+ public final static int KEY_ACTION = 0x08;
+
+
+ /**
+ * Direct access to writing data ...
+ * @param b
+ */
+ void write(byte b[]);
+
+ /**
+ * Terminal is mouse-aware and requires (x,y) coordinates of
+ * on the terminal (character coordinates) and the button clicked.
+ * @param x
+ * @param y
+ * @param modifiers
+ */
+ void mousePressed(int x, int y, int modifiers);
+
+ /**
+ * Terminal is mouse-aware and requires the coordinates and button
+ * of the release.
+ * @param x
+ * @param y
+ * @param modifiers
+ */
+ void mouseReleased(int x, int y, int modifiers);
+
+ /**
+ * Override the standard key codes used by the terminal emulation.
+ * @param codes a properties object containing key code definitions
+ */
+ void setKeyCodes(Properties codes);
+
+ /**
+ * main keytyping event handler...
+ * @param keyCode the key code
+ * @param keyChar the character represented by the key
+ * @param modifiers shift/alt/control modifiers
+ */
+ void keyPressed(int keyCode, char keyChar, int modifiers);
+
+ /**
+ * Handle key Typed events for the terminal, this will get
+ * all normal key types, but no shift/alt/control/numlock.
+ * @param keyCode the key code
+ * @param keyChar the character represented by the key
+ * @param modifiers shift/alt/control modifiers
+ */
+ void keyTyped(int keyCode, char keyChar, int modifiers);
+}
diff --git a/src/de/mud/terminal/vt320.java b/src/de/mud/terminal/vt320.java
new file mode 100644
index 0000000..099c877
--- /dev/null
+++ b/src/de/mud/terminal/vt320.java
@@ -0,0 +1,2722 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved.
+ *
+ * Please visit http://javatelnet.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ *
+ */
+
+package de.mud.terminal;
+
+import java.util.Properties;
+
+/**
+ * Implementation of a VT terminal emulation plus ANSI compatible.
+ * <P>
+ * <B>Maintainer:</B> Marcus Mei\u00dfner
+ *
+ * @version $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
+ * @author Matthias L. Jugel, Marcus Mei\u00dfner
+ */
+public abstract class vt320 extends VDUBuffer implements VDUInput {
+ /** The current version id tag.<P>
+ * $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
+ */
+ public final static String ID = "$Id: vt320.java 507 2005-10-25 10:14:52Z marcus $";
+
+ /** the debug level */
+ private final static int debug = 0;
+
+ /**
+ * Write an answer back to the remote host. This is needed to be able to
+ * send terminal answers requests like status and type information.
+ * @param b the array of bytes to be sent
+ */
+ public abstract void write(byte[] b);
+
+ /**
+ * Play the beep sound ...
+ */
+ public void beep() { /* do nothing by default */
+ }
+
+ /**
+ * Put string at current cursor position. Moves cursor
+ * according to the String. Does NOT wrap.
+ * @param s the string
+ */
+ public void putString(String s) {
+ int len = s.length();
+ // System.err.println("'"+s+"'");
+
+ if (len > 0) {
+ markLine(R, 1);
+ for (int i = 0; i < len; i++) {
+ // System.err.print(s.charAt(i)+"("+(int)s.charAt(i)+")");
+ putChar(s.charAt(i), false);
+ }
+ setCursorPosition(C, R);
+ redraw();
+ }
+ }
+
+ protected void sendTelnetCommand(byte cmd) {
+ }
+
+ /**
+ * Sent the changed window size from the terminal to all listeners.
+ */
+ protected void setWindowSize(int c, int r) {
+ /* To be overridden by Terminal.java */
+ }
+
+ public void setScreenSize(int c, int r, boolean broadcast) {
+ int oldrows = getRows();
+ //int oldcols = getColumns();
+
+ if (debug>2) System.err.println("setscreensize ("+c+","+r+","+broadcast+")");
+
+ super.setScreenSize(c,r,false);
+
+ /* Tricky, since the VDUBuffer works strangely. */
+ if (r > oldrows) {
+ setCursorPosition(C, R + (r-oldrows));
+ redraw();
+ }
+ if (broadcast) {
+ setWindowSize(c, r); /* broadcast up */
+ }
+ }
+
+
+ /**
+ * Create a new vt320 terminal and intialize it with useful settings.
+ */
+ public vt320(int width, int height) {
+ super(width, height);
+ setVMS(false);
+ setIBMCharset(false);
+ setTerminalID("vt320");
+ setBufferSize(100);
+ //setBorder(2, false);
+
+ int nw = getColumns();
+ if (nw < 132) nw = 132; //catch possible later 132/80 resizes
+ Tabs = new byte[nw];
+ for (int i = 0; i < nw; i += 8) {
+ Tabs[i] = 1;
+ }
+
+ /* top row of numpad */
+ PF1 = "\u001bOP";
+ PF2 = "\u001bOQ";
+ PF3 = "\u001bOR";
+ PF4 = "\u001bOS";
+
+ /* the 3x2 keyblock on PC keyboards */
+ Insert = new String[4];
+ Remove = new String[4];
+ KeyHome = new String[4];
+ KeyEnd = new String[4];
+ NextScn = new String[4];
+ PrevScn = new String[4];
+ Escape = new String[4];
+ BackSpace = new String[4];
+ TabKey = new String[4];
+ Insert[0] = Insert[1] = Insert[2] = Insert[3] = "\u001b[2~";
+ Remove[0] = Remove[1] = Remove[2] = Remove[3] = "\u001b[3~";
+ PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~";
+ NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~";
+ KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001b[H";
+ KeyEnd[0] = KeyEnd[1] = KeyEnd[2] = KeyEnd[3] = "\u001b[F";
+ Escape[0] = Escape[1] = Escape[2] = Escape[3] = "\u001b";
+ if (vms) {
+ BackSpace[1] = "" + (char) 10; // VMS shift deletes word back
+ BackSpace[2] = "\u0018"; // VMS control deletes line back
+ BackSpace[0] = BackSpace[3] = "\u007f"; // VMS other is delete
+ } else {
+ BackSpace[0] = BackSpace[1] = BackSpace[2] = BackSpace[3] = "\b";
+ }
+
+ /* some more VT100 keys */
+ Find = "\u001b[1~";
+ Select = "\u001b[4~";
+ Help = "\u001b[28~";
+ Do = "\u001b[29~";
+
+ FunctionKey = new String[21];
+ FunctionKey[0] = "";
+ FunctionKey[1] = PF1;
+ FunctionKey[2] = PF2;
+ FunctionKey[3] = PF3;
+ FunctionKey[4] = PF4;
+ /* following are defined differently for vt220 / vt132 ... */
+ FunctionKey[5] = "\u001b[15~";
+ FunctionKey[6] = "\u001b[17~";
+ FunctionKey[7] = "\u001b[18~";
+ FunctionKey[8] = "\u001b[19~";
+ FunctionKey[9] = "\u001b[20~";
+ FunctionKey[10] = "\u001b[21~";
+ FunctionKey[11] = "\u001b[23~";
+ FunctionKey[12] = "\u001b[24~";
+ FunctionKey[13] = "\u001b[25~";
+ FunctionKey[14] = "\u001b[26~";
+ FunctionKey[15] = Help;
+ FunctionKey[16] = Do;
+ FunctionKey[17] = "\u001b[31~";
+ FunctionKey[18] = "\u001b[32~";
+ FunctionKey[19] = "\u001b[33~";
+ FunctionKey[20] = "\u001b[34~";
+
+ FunctionKeyShift = new String[21];
+ FunctionKeyAlt = new String[21];
+ FunctionKeyCtrl = new String[21];
+
+ for (int i = 0; i < 20; i++) {
+ FunctionKeyShift[i] = "";
+ FunctionKeyAlt[i] = "";
+ FunctionKeyCtrl[i] = "";
+ }
+ FunctionKeyShift[15] = Find;
+ FunctionKeyShift[16] = Select;
+
+
+ TabKey[0] = "\u0009";
+ TabKey[1] = "\u001bOP\u0009";
+ TabKey[2] = TabKey[3] = "";
+
+ KeyUp = new String[4];
+ KeyUp[0] = "\u001b[A";
+ KeyDown = new String[4];
+ KeyDown[0] = "\u001b[B";
+ KeyRight = new String[4];
+ KeyRight[0] = "\u001b[C";
+ KeyLeft = new String[4];
+ KeyLeft[0] = "\u001b[D";
+ Numpad = new String[10];
+ Numpad[0] = "\u001bOp";
+ Numpad[1] = "\u001bOq";
+ Numpad[2] = "\u001bOr";
+ Numpad[3] = "\u001bOs";
+ Numpad[4] = "\u001bOt";
+ Numpad[5] = "\u001bOu";
+ Numpad[6] = "\u001bOv";
+ Numpad[7] = "\u001bOw";
+ Numpad[8] = "\u001bOx";
+ Numpad[9] = "\u001bOy";
+ KPMinus = PF4;
+ KPComma = "\u001bOl";
+ KPPeriod = "\u001bOn";
+ KPEnter = "\u001bOM";
+
+ NUMPlus = new String[4];
+ NUMPlus[0] = "+";
+ NUMDot = new String[4];
+ NUMDot[0] = ".";
+ }
+
+ /**
+ * Create a default vt320 terminal with 80 columns and 24 lines.
+ */
+ public vt320() {
+ this(80, 24);
+ }
+
+ /**
+ * Terminal is mouse-aware and requires (x,y) coordinates of
+ * on the terminal (character coordinates) and the button clicked.
+ * @param x
+ * @param y
+ * @param modifiers
+ */
+ public void mousePressed(int x, int y, int modifiers) {
+ if (mouserpt == 0)
+ return;
+
+ int mods = modifiers;
+ mousebut = 3;
+ if ((mods & 16) == 16) mousebut = 0;
+ if ((mods & 8) == 8) mousebut = 1;
+ if ((mods & 4) == 4) mousebut = 2;
+
+ int mousecode;
+ if (mouserpt == 9) /* X10 Mouse */
+ mousecode = 0x20 | mousebut;
+ else /* normal xterm mouse reporting */
+ mousecode = mousebut | 0x20 | ((mods & 7) << 2);
+
+ byte b[] = new byte[6];
+
+ b[0] = 27;
+ b[1] = (byte) '[';
+ b[2] = (byte) 'M';
+ b[3] = (byte) mousecode;
+ b[4] = (byte) (0x20 + x + 1);
+ b[5] = (byte) (0x20 + y + 1);
+
+ write(b); // FIXME: writeSpecial here
+ }
+
+ /**
+ * Terminal is mouse-aware and requires the coordinates and button
+ * of the release.
+ * @param x
+ * @param y
+ * @param modifiers
+ */
+ public void mouseReleased(int x, int y, int modifiers) {
+ if (mouserpt == 0)
+ return;
+
+ /* problem is tht modifiers still have the released button set in them.
+ int mods = modifiers;
+ mousebut = 3;
+ if ((mods & 16)==16) mousebut=0;
+ if ((mods & 8)==8 ) mousebut=1;
+ if ((mods & 4)==4 ) mousebut=2;
+ */
+
+ int mousecode;
+ if (mouserpt == 9)
+ mousecode = 0x20 + mousebut; /* same as press? appears so. */
+ else
+ mousecode = '#';
+
+ byte b[] = new byte[6];
+ b[0] = 27;
+ b[1] = (byte) '[';
+ b[2] = (byte) 'M';
+ b[3] = (byte) mousecode;
+ b[4] = (byte) (0x20 + x + 1);
+ b[5] = (byte) (0x20 + y + 1);
+ write(b); // FIXME: writeSpecial here
+ mousebut = 0;
+ }
+
+
+ /** we should do localecho (passed from other modules). false is default */
+ private boolean localecho = false;
+
+ /**
+ * Enable or disable the local echo property of the terminal.
+ * @param echo true if the terminal should echo locally
+ */
+ public void setLocalEcho(boolean echo) {
+ localecho = echo;
+ }
+
+ /**
+ * Enable the VMS mode of the terminal to handle some things differently
+ * for VMS hosts.
+ * @param vms true for vms mode, false for normal mode
+ */
+ public void setVMS(boolean vms) {
+ this.vms = vms;
+ }
+
+ /**
+ * Enable the usage of the IBM character set used by some BBS's. Special
+ * graphical character are available in this mode.
+ * @param ibm true to use the ibm character set
+ */
+ public void setIBMCharset(boolean ibm) {
+ useibmcharset = ibm;
+ }
+
+ /**
+ * Override the standard key codes used by the terminal emulation.
+ * @param codes a properties object containing key code definitions
+ */
+ public void setKeyCodes(Properties codes) {
+ String res, prefixes[] = {"", "S", "C", "A"};
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ res = codes.getProperty("NUMPAD" + i);
+ if (res != null) Numpad[i] = unEscape(res);
+ }
+ for (i = 1; i < 20; i++) {
+ res = codes.getProperty("F" + i);
+ if (res != null) FunctionKey[i] = unEscape(res);
+ res = codes.getProperty("SF" + i);
+ if (res != null) FunctionKeyShift[i] = unEscape(res);
+ res = codes.getProperty("CF" + i);
+ if (res != null) FunctionKeyCtrl[i] = unEscape(res);
+ res = codes.getProperty("AF" + i);
+ if (res != null) FunctionKeyAlt[i] = unEscape(res);
+ }
+ for (i = 0; i < 4; i++) {
+ res = codes.getProperty(prefixes[i] + "PGUP");
+ if (res != null) PrevScn[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "PGDOWN");
+ if (res != null) NextScn[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "END");
+ if (res != null) KeyEnd[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "HOME");
+ if (res != null) KeyHome[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "INSERT");
+ if (res != null) Insert[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "REMOVE");
+ if (res != null) Remove[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "UP");
+ if (res != null) KeyUp[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "DOWN");
+ if (res != null) KeyDown[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "LEFT");
+ if (res != null) KeyLeft[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "RIGHT");
+ if (res != null) KeyRight[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "ESCAPE");
+ if (res != null) Escape[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "BACKSPACE");
+ if (res != null) BackSpace[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "TAB");
+ if (res != null) TabKey[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "NUMPLUS");
+ if (res != null) NUMPlus[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "NUMDECIMAL");
+ if (res != null) NUMDot[i] = unEscape(res);
+ }
+ }
+
+ /**
+ * Set the terminal id used to identify this terminal.
+ * @param terminalID the id string
+ */
+ public void setTerminalID(String terminalID) {
+ this.terminalID = terminalID;
+
+ if (terminalID.equals("scoansi")) {
+ FunctionKey[1] = "\u001b[M"; FunctionKey[2] = "\u001b[N";
+ FunctionKey[3] = "\u001b[O"; FunctionKey[4] = "\u001b[P";
+ FunctionKey[5] = "\u001b[Q"; FunctionKey[6] = "\u001b[R";
+ FunctionKey[7] = "\u001b[S"; FunctionKey[8] = "\u001b[T";
+ FunctionKey[9] = "\u001b[U"; FunctionKey[10] = "\u001b[V";
+ FunctionKey[11] = "\u001b[W"; FunctionKey[12] = "\u001b[X";
+ FunctionKey[13] = "\u001b[Y"; FunctionKey[14] = "?";
+ FunctionKey[15] = "\u001b[a"; FunctionKey[16] = "\u001b[b";
+ FunctionKey[17] = "\u001b[c"; FunctionKey[18] = "\u001b[d";
+ FunctionKey[19] = "\u001b[e"; FunctionKey[20] = "\u001b[f";
+ PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[I";
+ NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[G";
+ // more theoretically.
+ }
+ }
+
+ public void setAnswerBack(String ab) {
+ this.answerBack = unEscape(ab);
+ }
+
+ /**
+ * Get the terminal id used to identify this terminal.
+ */
+ public String getTerminalID() {
+ return terminalID;
+ }
+
+ /**
+ * A small conveniance method thar converts the string to a byte array
+ * for sending.
+ * @param s the string to be sent
+ */
+ private boolean write(String s, boolean doecho) {
+ if (debug > 2) System.out.println("write(|" + s + "|," + doecho);
+ if (s == null) // aka the empty string.
+ return true;
+ /* NOTE: getBytes() honours some locale, it *CONVERTS* the string.
+ * However, we output only 7bit stuff towards the target, and *some*
+ * 8 bit control codes. We must not mess up the latter, so we do hand
+ * by hand copy.
+ */
+
+ byte arr[] = new byte[s.length()];
+ for (int i = 0; i < s.length(); i++) {
+ arr[i] = (byte) s.charAt(i);
+ }
+ write(arr);
+
+ if (doecho)
+ putString(s);
+ return true;
+ }
+
+ private boolean write(String s) {
+ return write(s, localecho);
+ }
+
+ // ===================================================================
+ // the actual terminal emulation code comes here:
+ // ===================================================================
+
+ private String terminalID = "vt320";
+ private String answerBack = "Use Terminal.answerback to set ...\n";
+
+ // X - COLUMNS, Y - ROWS
+ int R,C;
+ int attributes = 0;
+
+ int Sc,Sr,Sa,Stm,Sbm;
+ char Sgr,Sgl;
+ char Sgx[];
+
+ int insertmode = 0;
+ int statusmode = 0;
+ boolean vt52mode = false;
+ boolean keypadmode = false; /* false - numeric, true - application */
+ boolean output8bit = false;
+ int normalcursor = 0;
+ boolean moveoutsidemargins = true;
+ boolean wraparound = true;
+ boolean sendcrlf = true;
+ boolean capslock = false;
+ boolean numlock = false;
+ int mouserpt = 0;
+ byte mousebut = 0;
+
+ boolean useibmcharset = false;
+
+ int lastwaslf = 0;
+ boolean usedcharsets = false;
+
+ private final static char ESC = 27;
+ private final static char IND = 132;
+ private final static char NEL = 133;
+ private final static char RI = 141;
+ private final static char SS2 = 142;
+ private final static char SS3 = 143;
+ private final static char DCS = 144;
+ private final static char HTS = 136;
+ private final static char CSI = 155;
+ private final static char OSC = 157;
+ private final static int TSTATE_DATA = 0;
+ private final static int TSTATE_ESC = 1; /* ESC */
+ private final static int TSTATE_CSI = 2; /* ESC [ */
+ private final static int TSTATE_DCS = 3; /* ESC P */
+ private final static int TSTATE_DCEQ = 4; /* ESC [? */
+ private final static int TSTATE_ESCSQUARE = 5; /* ESC # */
+ private final static int TSTATE_OSC = 6; /* ESC ] */
+ private final static int TSTATE_SETG0 = 7; /* ESC (? */
+ private final static int TSTATE_SETG1 = 8; /* ESC )? */
+ private final static int TSTATE_SETG2 = 9; /* ESC *? */
+ private final static int TSTATE_SETG3 = 10; /* ESC +? */
+ private final static int TSTATE_CSI_DOLLAR = 11; /* ESC [ Pn $ */
+ private final static int TSTATE_CSI_EX = 12; /* ESC [ ! */
+ private final static int TSTATE_ESCSPACE = 13; /* ESC <space> */
+ private final static int TSTATE_VT52X = 14;
+ private final static int TSTATE_VT52Y = 15;
+ private final static int TSTATE_CSI_TICKS = 16;
+ private final static int TSTATE_CSI_EQUAL = 17; /* ESC [ = */
+
+ /* Keys we support */
+ public final static int KEY_PAUSE = 1;
+ public final static int KEY_F1 = 2;
+ public final static int KEY_F2 = 3;
+ public final static int KEY_F3 = 4;
+ public final static int KEY_F4 = 5;
+ public final static int KEY_F5 = 6;
+ public final static int KEY_F6 = 7;
+ public final static int KEY_F7 = 8;
+ public final static int KEY_F8 = 9;
+ public final static int KEY_F9 = 10;
+ public final static int KEY_F10 = 11;
+ public final static int KEY_F11 = 12;
+ public final static int KEY_F12 = 13;
+ public final static int KEY_UP = 14;
+ public final static int KEY_DOWN =15 ;
+ public final static int KEY_LEFT = 16;
+ public final static int KEY_RIGHT = 17;
+ public final static int KEY_PAGE_DOWN = 18;
+ public final static int KEY_PAGE_UP = 19;
+ public final static int KEY_INSERT = 20;
+ public final static int KEY_DELETE = 21;
+ public final static int KEY_BACK_SPACE = 22;
+ public final static int KEY_HOME = 23;
+ public final static int KEY_END = 24;
+ public final static int KEY_NUM_LOCK = 25;
+ public final static int KEY_CAPS_LOCK = 26;
+ public final static int KEY_SHIFT = 27;
+ public final static int KEY_CONTROL = 28;
+ public final static int KEY_ALT = 29;
+ public final static int KEY_ENTER = 30;
+ public final static int KEY_NUMPAD0 = 31;
+ public final static int KEY_NUMPAD1 = 32;
+ public final static int KEY_NUMPAD2 = 33;
+ public final static int KEY_NUMPAD3 = 34;
+ public final static int KEY_NUMPAD4 = 35;
+ public final static int KEY_NUMPAD5 = 36;
+ public final static int KEY_NUMPAD6 = 37;
+ public final static int KEY_NUMPAD7 = 38;
+ public final static int KEY_NUMPAD8 = 39;
+ public final static int KEY_NUMPAD9 = 40;
+ public final static int KEY_DECIMAL = 41;
+ public final static int KEY_ADD = 42;
+ public final static int KEY_ESCAPE = 43;
+
+ /* The graphics charsets
+ * B - default ASCII
+ * A - ISO Latin 1
+ * 0 - DEC SPECIAL
+ * < - User defined
+ * ....
+ */
+ char gx[] = {// same initial set as in XTERM.
+ 'B', // g0
+ '0', // g1
+ 'B', // g2
+ 'B', // g3
+ };
+ char gl = 0; // default GL to G0
+ char gr = 2; // default GR to G2
+ int onegl = -1; // single shift override for GL.
+
+ // Map from scoansi linedrawing to DEC _and_ unicode (for the stuff which
+ // is not in linedrawing). Got from experimenting with scoadmin.
+ private final static String scoansi_acs = "Tm7k3x4u?kZl@mYjEnB\u2566DqCtAvM\u2550:\u2551N\u2557I\u2554;\u2557H\u255a0a<\u255d";
+ // array to store DEC Special -> Unicode mapping
+ // Unicode DEC Unicode name (DEC name)
+ private static char DECSPECIAL[] = {
+ '\u0040', //5f blank
+ '\u2666', //60 black diamond
+ '\u2592', //61 grey square
+ '\u2409', //62 Horizontal tab (ht) pict. for control
+ '\u240c', //63 Form Feed (ff) pict. for control
+ '\u240d', //64 Carriage Return (cr) pict. for control
+ '\u240a', //65 Line Feed (lf) pict. for control
+ '\u00ba', //66 Masculine ordinal indicator
+ '\u00b1', //67 Plus or minus sign
+ '\u2424', //68 New Line (nl) pict. for control
+ '\u240b', //69 Vertical Tab (vt) pict. for control
+ '\u2518', //6a Forms light up and left
+ '\u2510', //6b Forms light down and left
+ '\u250c', //6c Forms light down and right
+ '\u2514', //6d Forms light up and right
+ '\u253c', //6e Forms light vertical and horizontal
+ '\u2594', //6f Upper 1/8 block (Scan 1)
+ '\u2580', //70 Upper 1/2 block (Scan 3)
+ '\u2500', //71 Forms light horizontal or ?em dash? (Scan 5)
+ '\u25ac', //72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7)
+ '\u005f', //73 \u005f underscore or \u2581 lower 1/8 (Scan 9)
+ '\u251c', //74 Forms light vertical and right
+ '\u2524', //75 Forms light vertical and left
+ '\u2534', //76 Forms light up and horizontal
+ '\u252c', //77 Forms light down and horizontal
+ '\u2502', //78 vertical bar
+ '\u2264', //79 less than or equal
+ '\u2265', //7a greater than or equal
+ '\u00b6', //7b paragraph
+ '\u2260', //7c not equal
+ '\u00a3', //7d Pound Sign (british)
+ '\u00b7' //7e Middle Dot
+ };
+
+ /** Strings to send on function key pressing */
+ private String Numpad[];
+ private String FunctionKey[];
+ private String FunctionKeyShift[];
+ private String FunctionKeyCtrl[];
+ private String FunctionKeyAlt[];
+ private String TabKey[];
+ private String KeyUp[],KeyDown[],KeyLeft[],KeyRight[];
+ private String KPMinus, KPComma, KPPeriod, KPEnter;
+ private String PF1, PF2, PF3, PF4;
+ private String Help, Do, Find, Select;
+
+ private String KeyHome[], KeyEnd[], Insert[], Remove[], PrevScn[], NextScn[];
+ private String Escape[], BackSpace[], NUMDot[], NUMPlus[];
+
+ private String osc,dcs; /* to memorize OSC & DCS control sequence */
+
+ /** vt320 state variable (internal) */
+ private int term_state = TSTATE_DATA;
+ /** in vms mode, set by Terminal.VMS property */
+ private boolean vms = false;
+ /** Tabulators */
+ private byte[] Tabs;
+ /** The list of integers as used by CSI */
+ private int[] DCEvars = new int[30];
+ private int DCEvar;
+
+ /**
+ * Replace escape code characters (backslash + identifier) with their
+ * respective codes.
+ * @param tmp the string to be parsed
+ * @return a unescaped string
+ */
+ static String unEscape(String tmp) {
+ int idx = 0, oldidx = 0;
+ String cmd;
+ // System.err.println("unescape("+tmp+")");
+ cmd = "";
+ while ((idx = tmp.indexOf('\\', oldidx)) >= 0 &&
+ ++idx <= tmp.length()) {
+ cmd += tmp.substring(oldidx, idx - 1);
+ if (idx == tmp.length()) return cmd;
+ switch (tmp.charAt(idx)) {
+ case 'b':
+ cmd += "\b";
+ break;
+ case 'e':
+ cmd += "\u001b";
+ break;
+ case 'n':
+ cmd += "\n";
+ break;
+ case 'r':
+ cmd += "\r";
+ break;
+ case 't':
+ cmd += "\t";
+ break;
+ case 'v':
+ cmd += "\u000b";
+ break;
+ case 'a':
+ cmd += "\u0012";
+ break;
+ default :
+ if ((tmp.charAt(idx) >= '0') && (tmp.charAt(idx) <= '9')) {
+ int i;
+ for (i = idx; i < tmp.length(); i++)
+ if ((tmp.charAt(i) < '0') || (tmp.charAt(i) > '9'))
+ break;
+ cmd += (char) Integer.parseInt(tmp.substring(idx, i));
+ idx = i - 1;
+ } else
+ cmd += tmp.substring(idx, ++idx);
+ break;
+ }
+ oldidx = ++idx;
+ }
+ if (oldidx <= tmp.length()) cmd += tmp.substring(oldidx);
+ return cmd;
+ }
+
+ /**
+ * A small conveniance method thar converts a 7bit string to the 8bit
+ * version depending on VT52/Output8Bit mode.
+ *
+ * @param s the string to be sent
+ */
+ private boolean writeSpecial(String s) {
+ if (s == null)
+ return true;
+ if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == 'O'))) {
+ if (vt52mode) {
+ if ((s.charAt(2) >= 'P') && (s.charAt(2) <= 'S')) {
+ s = "\u001b" + s.substring(2); /* ESC x */
+ } else {
+ s = "\u001b?" + s.substring(2); /* ESC ? x */
+ }
+ } else {
+ if (output8bit) {
+ s = "\u008f" + s.substring(2); /* SS3 x */
+ } /* else keep string as it is */
+ }
+ }
+ if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == '['))) {
+ if (output8bit) {
+ s = "\u009b" + s.substring(2); /* CSI ... */
+ } /* else keep */
+ }
+ return write(s, false);
+ }
+
+ /**
+ * main keytyping event handler...
+ */
+ public void keyPressed(int keyCode, char keyChar, int modifiers) {
+ boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
+ boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
+ boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
+
+ if (debug > 1) System.out.println("keyPressed("+keyCode+", "+(int)keyChar+", "+modifiers+")");
+
+ int xind;
+ String fmap[];
+ xind = 0;
+ fmap = FunctionKey;
+ if (shift) {
+ fmap = FunctionKeyShift;
+ xind = 1;
+ }
+ if (control) {
+ fmap = FunctionKeyCtrl;
+ xind = 2;
+ }
+ if (alt) {
+ fmap = FunctionKeyAlt;
+ xind = 3;
+ }
+
+ switch (keyCode) {
+ case KEY_PAUSE:
+ if (shift || control)
+ sendTelnetCommand((byte) 243); // BREAK
+ break;
+ case KEY_F1:
+ writeSpecial(fmap[1]);
+ break;
+ case KEY_F2:
+ writeSpecial(fmap[2]);
+ break;
+ case KEY_F3:
+ writeSpecial(fmap[3]);
+ break;
+ case KEY_F4:
+ writeSpecial(fmap[4]);
+ break;
+ case KEY_F5:
+ writeSpecial(fmap[5]);
+ break;
+ case KEY_F6:
+ writeSpecial(fmap[6]);
+ break;
+ case KEY_F7:
+ writeSpecial(fmap[7]);
+ break;
+ case KEY_F8:
+ writeSpecial(fmap[8]);
+ break;
+ case KEY_F9:
+ writeSpecial(fmap[9]);
+ break;
+ case KEY_F10:
+ writeSpecial(fmap[10]);
+ break;
+ case KEY_F11:
+ writeSpecial(fmap[11]);
+ break;
+ case KEY_F12:
+ writeSpecial(fmap[12]);
+ break;
+ case KEY_UP:
+ writeSpecial(KeyUp[xind]);
+ break;
+ case KEY_DOWN:
+ writeSpecial(KeyDown[xind]);
+ break;
+ case KEY_LEFT:
+ writeSpecial(KeyLeft[xind]);
+ break;
+ case KEY_RIGHT:
+ writeSpecial(KeyRight[xind]);
+ break;
+ case KEY_PAGE_DOWN:
+ writeSpecial(NextScn[xind]);
+ break;
+ case KEY_PAGE_UP:
+ writeSpecial(PrevScn[xind]);
+ break;
+ case KEY_INSERT:
+ writeSpecial(Insert[xind]);
+ break;
+ case KEY_DELETE:
+ writeSpecial(Remove[xind]);
+ break;
+ case KEY_BACK_SPACE:
+ writeSpecial(BackSpace[xind]);
+ if (localecho) {
+ if (BackSpace[xind] == "\b") {
+ putString("\b \b"); // make the last char 'deleted'
+ } else {
+ putString(BackSpace[xind]); // echo it
+ }
+ }
+ break;
+ case KEY_HOME:
+ writeSpecial(KeyHome[xind]);
+ break;
+ case KEY_END:
+ writeSpecial(KeyEnd[xind]);
+ break;
+ case KEY_NUM_LOCK:
+ if (vms && control) {
+ writeSpecial(PF1);
+ }
+ if (!control)
+ numlock = !numlock;
+ break;
+ case KEY_CAPS_LOCK:
+ capslock = !capslock;
+ return;
+ case KEY_SHIFT:
+ case KEY_CONTROL:
+ case KEY_ALT:
+ return;
+ default:
+ break;
+ }
+ }
+/*
+ public void keyReleased(KeyEvent evt) {
+ if (debug > 1) System.out.println("keyReleased("+evt+")");
+ // ignore
+ }
+*/
+ /**
+ * Handle key Typed events for the terminal, this will get
+ * all normal key types, but no shift/alt/control/numlock.
+ */
+ public void keyTyped(int keyCode, char keyChar, int modifiers) {
+ boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
+ boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
+ boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
+
+ if (debug > 1) System.out.println("keyTyped("+keyCode+", "+(int)keyChar+", "+modifiers+")");
+
+ if (keyChar == '\t') {
+ if (shift) {
+ write(TabKey[1], false);
+ } else {
+ if (control) {
+ write(TabKey[2], false);
+ } else {
+ if (alt) {
+ write(TabKey[3], false);
+ } else {
+ write(TabKey[0], false);
+ }
+ }
+ }
+ return;
+ }
+ if (alt) {
+ write("" + ((char) (keyChar | 0x80)));
+ return;
+ }
+
+ if (((keyCode == KEY_ENTER) || (keyChar == 10))
+ && !control) {
+ write("\r", false);
+ if (localecho) putString("\r\n"); // bad hack
+ return;
+ }
+
+ if ((keyCode == 10) && !control) {
+ System.out.println("Sending \\r");
+ write("\r", false);
+ return;
+ }
+
+ // FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @,
+ // so we can't just use it here... will probably break some other VMS
+ // codes. -Marcus
+ // if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ')
+ // && control)
+ if (((!vms && keyChar == '2') || keyChar == ' ') && control)
+ write("" + (char) 0);
+
+ if (vms) {
+ if (keyChar == 127 && !control) {
+ if (shift)
+ writeSpecial(Insert[0]); // VMS shift delete = insert
+ else
+ writeSpecial(Remove[0]); // VMS delete = remove
+ return;
+ } else if (control)
+ switch (keyChar) {
+ case '0':
+ writeSpecial(Numpad[0]);
+ return;
+ case '1':
+ writeSpecial(Numpad[1]);
+ return;
+ case '2':
+ writeSpecial(Numpad[2]);
+ return;
+ case '3':
+ writeSpecial(Numpad[3]);
+ return;
+ case '4':
+ writeSpecial(Numpad[4]);
+ return;
+ case '5':
+ writeSpecial(Numpad[5]);
+ return;
+ case '6':
+ writeSpecial(Numpad[6]);
+ return;
+ case '7':
+ writeSpecial(Numpad[7]);
+ return;
+ case '8':
+ writeSpecial(Numpad[8]);
+ return;
+ case '9':
+ writeSpecial(Numpad[9]);
+ return;
+ case '.':
+ writeSpecial(KPPeriod);
+ return;
+ case '-':
+ case 31:
+ writeSpecial(KPMinus);
+ return;
+ case '+':
+ writeSpecial(KPComma);
+ return;
+ case 10:
+ writeSpecial(KPEnter);
+ return;
+ case '/':
+ writeSpecial(PF2);
+ return;
+ case '*':
+ writeSpecial(PF3);
+ return;
+ /* NUMLOCK handled in keyPressed */
+ default:
+ break;
+ }
+ /* Now what does this do and how did it get here. -Marcus
+ if (shift && keyChar < 32) {
+ write(PF1+(char)(keyChar + 64));
+ return;
+ }
+ */
+ }
+
+ // FIXME: not used?
+ //String fmap[];
+ int xind;
+ xind = 0;
+ //fmap = FunctionKey;
+ if (shift) {
+ //fmap = FunctionKeyShift;
+ xind = 1;
+ }
+ if (control) {
+ //fmap = FunctionKeyCtrl;
+ xind = 2;
+ }
+ if (alt) {
+ //fmap = FunctionKeyAlt;
+ xind = 3;
+ }
+
+ if (keyCode == KEY_ESCAPE) {
+ writeSpecial(Escape[xind]);
+ return;
+ }
+
+ if ((modifiers & VDUInput.KEY_ACTION) != 0)
+ switch (keyCode) {
+ case KEY_NUMPAD0:
+ writeSpecial(Numpad[0]);
+ return;
+ case KEY_NUMPAD1:
+ writeSpecial(Numpad[1]);
+ return;
+ case KEY_NUMPAD2:
+ writeSpecial(Numpad[2]);
+ return;
+ case KEY_NUMPAD3:
+ writeSpecial(Numpad[3]);
+ return;
+ case KEY_NUMPAD4:
+ writeSpecial(Numpad[4]);
+ return;
+ case KEY_NUMPAD5:
+ writeSpecial(Numpad[5]);
+ return;
+ case KEY_NUMPAD6:
+ writeSpecial(Numpad[6]);
+ return;
+ case KEY_NUMPAD7:
+ writeSpecial(Numpad[7]);
+ return;
+ case KEY_NUMPAD8:
+ writeSpecial(Numpad[8]);
+ return;
+ case KEY_NUMPAD9:
+ writeSpecial(Numpad[9]);
+ return;
+ case KEY_DECIMAL:
+ writeSpecial(NUMDot[xind]);
+ return;
+ case KEY_ADD:
+ writeSpecial(NUMPlus[xind]);
+ return;
+ }
+
+ if (!((keyChar == 8) || (keyChar == 127) || (keyChar == '\r') || (keyChar == '\n'))) {
+ write("" + keyChar);
+ return;
+ }
+ }
+
+ private void handle_dcs(String dcs) {
+ System.out.println("DCS: " + dcs);
+ }
+
+ private void handle_osc(String osc) {
+ System.out.println("OSC: " + osc);
+ }
+
+ private final static char unimap[] = {
+ //#
+ //# Name: cp437_DOSLatinUS to Unicode table
+ //# Unicode version: 1.1
+ //# Table version: 1.1
+ //# Table format: Format A
+ //# Date: 03/31/95
+ //# Authors: Michel Suignard <michelsu@microsoft.com>
+ //# Lori Hoerth <lorih@microsoft.com>
+ //# General notes: none
+ //#
+ //# Format: Three tab-separated columns
+ //# Column #1 is the cp1255_WinHebrew code (in hex)
+ //# Column #2 is the Unicode (in hex as 0xXXXX)
+ //# Column #3 is the Unicode name (follows a comment sign, '#')
+ //#
+ //# The entries are in cp437_DOSLatinUS order
+ //#
+
+ 0x0000, // #NULL
+ 0x0001, // #START OF HEADING
+ 0x0002, // #START OF TEXT
+ 0x0003, // #END OF TEXT
+ 0x0004, // #END OF TRANSMISSION
+ 0x0005, // #ENQUIRY
+ 0x0006, // #ACKNOWLEDGE
+ 0x0007, // #BELL
+ 0x0008, // #BACKSPACE
+ 0x0009, // #HORIZONTAL TABULATION
+ 0x000a, // #LINE FEED
+ 0x000b, // #VERTICAL TABULATION
+ 0x000c, // #FORM FEED
+ 0x000d, // #CARRIAGE RETURN
+ 0x000e, // #SHIFT OUT
+ 0x000f, // #SHIFT IN
+ 0x0010, // #DATA LINK ESCAPE
+ 0x0011, // #DEVICE CONTROL ONE
+ 0x0012, // #DEVICE CONTROL TWO
+ 0x0013, // #DEVICE CONTROL THREE
+ 0x0014, // #DEVICE CONTROL FOUR
+ 0x0015, // #NEGATIVE ACKNOWLEDGE
+ 0x0016, // #SYNCHRONOUS IDLE
+ 0x0017, // #END OF TRANSMISSION BLOCK
+ 0x0018, // #CANCEL
+ 0x0019, // #END OF MEDIUM
+ 0x001a, // #SUBSTITUTE
+ 0x001b, // #ESCAPE
+ 0x001c, // #FILE SEPARATOR
+ 0x001d, // #GROUP SEPARATOR
+ 0x001e, // #RECORD SEPARATOR
+ 0x001f, // #UNIT SEPARATOR
+ 0x0020, // #SPACE
+ 0x0021, // #EXCLAMATION MARK
+ 0x0022, // #QUOTATION MARK
+ 0x0023, // #NUMBER SIGN
+ 0x0024, // #DOLLAR SIGN
+ 0x0025, // #PERCENT SIGN
+ 0x0026, // #AMPERSAND
+ 0x0027, // #APOSTROPHE
+ 0x0028, // #LEFT PARENTHESIS
+ 0x0029, // #RIGHT PARENTHESIS
+ 0x002a, // #ASTERISK
+ 0x002b, // #PLUS SIGN
+ 0x002c, // #COMMA
+ 0x002d, // #HYPHEN-MINUS
+ 0x002e, // #FULL STOP
+ 0x002f, // #SOLIDUS
+ 0x0030, // #DIGIT ZERO
+ 0x0031, // #DIGIT ONE
+ 0x0032, // #DIGIT TWO
+ 0x0033, // #DIGIT THREE
+ 0x0034, // #DIGIT FOUR
+ 0x0035, // #DIGIT FIVE
+ 0x0036, // #DIGIT SIX
+ 0x0037, // #DIGIT SEVEN
+ 0x0038, // #DIGIT EIGHT
+ 0x0039, // #DIGIT NINE
+ 0x003a, // #COLON
+ 0x003b, // #SEMICOLON
+ 0x003c, // #LESS-THAN SIGN
+ 0x003d, // #EQUALS SIGN
+ 0x003e, // #GREATER-THAN SIGN
+ 0x003f, // #QUESTION MARK
+ 0x0040, // #COMMERCIAL AT
+ 0x0041, // #LATIN CAPITAL LETTER A
+ 0x0042, // #LATIN CAPITAL LETTER B
+ 0x0043, // #LATIN CAPITAL LETTER C
+ 0x0044, // #LATIN CAPITAL LETTER D
+ 0x0045, // #LATIN CAPITAL LETTER E
+ 0x0046, // #LATIN CAPITAL LETTER F
+ 0x0047, // #LATIN CAPITAL LETTER G
+ 0x0048, // #LATIN CAPITAL LETTER H
+ 0x0049, // #LATIN CAPITAL LETTER I
+ 0x004a, // #LATIN CAPITAL LETTER J
+ 0x004b, // #LATIN CAPITAL LETTER K
+ 0x004c, // #LATIN CAPITAL LETTER L
+ 0x004d, // #LATIN CAPITAL LETTER M
+ 0x004e, // #LATIN CAPITAL LETTER N
+ 0x004f, // #LATIN CAPITAL LETTER O
+ 0x0050, // #LATIN CAPITAL LETTER P
+ 0x0051, // #LATIN CAPITAL LETTER Q
+ 0x0052, // #LATIN CAPITAL LETTER R
+ 0x0053, // #LATIN CAPITAL LETTER S
+ 0x0054, // #LATIN CAPITAL LETTER T
+ 0x0055, // #LATIN CAPITAL LETTER U
+ 0x0056, // #LATIN CAPITAL LETTER V
+ 0x0057, // #LATIN CAPITAL LETTER W
+ 0x0058, // #LATIN CAPITAL LETTER X
+ 0x0059, // #LATIN CAPITAL LETTER Y
+ 0x005a, // #LATIN CAPITAL LETTER Z
+ 0x005b, // #LEFT SQUARE BRACKET
+ 0x005c, // #REVERSE SOLIDUS
+ 0x005d, // #RIGHT SQUARE BRACKET
+ 0x005e, // #CIRCUMFLEX ACCENT
+ 0x005f, // #LOW LINE
+ 0x0060, // #GRAVE ACCENT
+ 0x0061, // #LATIN SMALL LETTER A
+ 0x0062, // #LATIN SMALL LETTER B
+ 0x0063, // #LATIN SMALL LETTER C
+ 0x0064, // #LATIN SMALL LETTER D
+ 0x0065, // #LATIN SMALL LETTER E
+ 0x0066, // #LATIN SMALL LETTER F
+ 0x0067, // #LATIN SMALL LETTER G
+ 0x0068, // #LATIN SMALL LETTER H
+ 0x0069, // #LATIN SMALL LETTER I
+ 0x006a, // #LATIN SMALL LETTER J
+ 0x006b, // #LATIN SMALL LETTER K
+ 0x006c, // #LATIN SMALL LETTER L
+ 0x006d, // #LATIN SMALL LETTER M
+ 0x006e, // #LATIN SMALL LETTER N
+ 0x006f, // #LATIN SMALL LETTER O
+ 0x0070, // #LATIN SMALL LETTER P
+ 0x0071, // #LATIN SMALL LETTER Q
+ 0x0072, // #LATIN SMALL LETTER R
+ 0x0073, // #LATIN SMALL LETTER S
+ 0x0074, // #LATIN SMALL LETTER T
+ 0x0075, // #LATIN SMALL LETTER U
+ 0x0076, // #LATIN SMALL LETTER V
+ 0x0077, // #LATIN SMALL LETTER W
+ 0x0078, // #LATIN SMALL LETTER X
+ 0x0079, // #LATIN SMALL LETTER Y
+ 0x007a, // #LATIN SMALL LETTER Z
+ 0x007b, // #LEFT CURLY BRACKET
+ 0x007c, // #VERTICAL LINE
+ 0x007d, // #RIGHT CURLY BRACKET
+ 0x007e, // #TILDE
+ 0x007f, // #DELETE
+ 0x00c7, // #LATIN CAPITAL LETTER C WITH CEDILLA
+ 0x00fc, // #LATIN SMALL LETTER U WITH DIAERESIS
+ 0x00e9, // #LATIN SMALL LETTER E WITH ACUTE
+ 0x00e2, // #LATIN SMALL LETTER A WITH CIRCUMFLEX
+ 0x00e4, // #LATIN SMALL LETTER A WITH DIAERESIS
+ 0x00e0, // #LATIN SMALL LETTER A WITH GRAVE
+ 0x00e5, // #LATIN SMALL LETTER A WITH RING ABOVE
+ 0x00e7, // #LATIN SMALL LETTER C WITH CEDILLA
+ 0x00ea, // #LATIN SMALL LETTER E WITH CIRCUMFLEX
+ 0x00eb, // #LATIN SMALL LETTER E WITH DIAERESIS
+ 0x00e8, // #LATIN SMALL LETTER E WITH GRAVE
+ 0x00ef, // #LATIN SMALL LETTER I WITH DIAERESIS
+ 0x00ee, // #LATIN SMALL LETTER I WITH CIRCUMFLEX
+ 0x00ec, // #LATIN SMALL LETTER I WITH GRAVE
+ 0x00c4, // #LATIN CAPITAL LETTER A WITH DIAERESIS
+ 0x00c5, // #LATIN CAPITAL LETTER A WITH RING ABOVE
+ 0x00c9, // #LATIN CAPITAL LETTER E WITH ACUTE
+ 0x00e6, // #LATIN SMALL LIGATURE AE
+ 0x00c6, // #LATIN CAPITAL LIGATURE AE
+ 0x00f4, // #LATIN SMALL LETTER O WITH CIRCUMFLEX
+ 0x00f6, // #LATIN SMALL LETTER O WITH DIAERESIS
+ 0x00f2, // #LATIN SMALL LETTER O WITH GRAVE
+ 0x00fb, // #LATIN SMALL LETTER U WITH CIRCUMFLEX
+ 0x00f9, // #LATIN SMALL LETTER U WITH GRAVE
+ 0x00ff, // #LATIN SMALL LETTER Y WITH DIAERESIS
+ 0x00d6, // #LATIN CAPITAL LETTER O WITH DIAERESIS
+ 0x00dc, // #LATIN CAPITAL LETTER U WITH DIAERESIS
+ 0x00a2, // #CENT SIGN
+ 0x00a3, // #POUND SIGN
+ 0x00a5, // #YEN SIGN
+ 0x20a7, // #PESETA SIGN
+ 0x0192, // #LATIN SMALL LETTER F WITH HOOK
+ 0x00e1, // #LATIN SMALL LETTER A WITH ACUTE
+ 0x00ed, // #LATIN SMALL LETTER I WITH ACUTE
+ 0x00f3, // #LATIN SMALL LETTER O WITH ACUTE
+ 0x00fa, // #LATIN SMALL LETTER U WITH ACUTE
+ 0x00f1, // #LATIN SMALL LETTER N WITH TILDE
+ 0x00d1, // #LATIN CAPITAL LETTER N WITH TILDE
+ 0x00aa, // #FEMININE ORDINAL INDICATOR
+ 0x00ba, // #MASCULINE ORDINAL INDICATOR
+ 0x00bf, // #INVERTED QUESTION MARK
+ 0x2310, // #REVERSED NOT SIGN
+ 0x00ac, // #NOT SIGN
+ 0x00bd, // #VULGAR FRACTION ONE HALF
+ 0x00bc, // #VULGAR FRACTION ONE QUARTER
+ 0x00a1, // #INVERTED EXCLAMATION MARK
+ 0x00ab, // #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x00bb, // #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ 0x2591, // #LIGHT SHADE
+ 0x2592, // #MEDIUM SHADE
+ 0x2593, // #DARK SHADE
+ 0x2502, // #BOX DRAWINGS LIGHT VERTICAL
+ 0x2524, // #BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ 0x2561, // #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ 0x2562, // #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ 0x2556, // #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ 0x2555, // #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ 0x2563, // #BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ 0x2551, // #BOX DRAWINGS DOUBLE VERTICAL
+ 0x2557, // #BOX DRAWINGS DOUBLE DOWN AND LEFT
+ 0x255d, // #BOX DRAWINGS DOUBLE UP AND LEFT
+ 0x255c, // #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ 0x255b, // #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ 0x2510, // #BOX DRAWINGS LIGHT DOWN AND LEFT
+ 0x2514, // #BOX DRAWINGS LIGHT UP AND RIGHT
+ 0x2534, // #BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ 0x252c, // #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ 0x251c, // #BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ 0x2500, // #BOX DRAWINGS LIGHT HORIZONTAL
+ 0x253c, // #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ 0x255e, // #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ 0x255f, // #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ 0x255a, // #BOX DRAWINGS DOUBLE UP AND RIGHT
+ 0x2554, // #BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ 0x2569, // #BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ 0x2566, // #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ 0x2560, // #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ 0x2550, // #BOX DRAWINGS DOUBLE HORIZONTAL
+ 0x256c, // #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ 0x2567, // #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ 0x2568, // #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ 0x2564, // #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ 0x2565, // #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ 0x2559, // #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ 0x2558, // #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ 0x2552, // #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ 0x2553, // #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ 0x256b, // #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ 0x256a, // #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ 0x2518, // #BOX DRAWINGS LIGHT UP AND LEFT
+ 0x250c, // #BOX DRAWINGS LIGHT DOWN AND RIGHT
+ 0x2588, // #FULL BLOCK
+ 0x2584, // #LOWER HALF BLOCK
+ 0x258c, // #LEFT HALF BLOCK
+ 0x2590, // #RIGHT HALF BLOCK
+ 0x2580, // #UPPER HALF BLOCK
+ 0x03b1, // #GREEK SMALL LETTER ALPHA
+ 0x00df, // #LATIN SMALL LETTER SHARP S
+ 0x0393, // #GREEK CAPITAL LETTER GAMMA
+ 0x03c0, // #GREEK SMALL LETTER PI
+ 0x03a3, // #GREEK CAPITAL LETTER SIGMA
+ 0x03c3, // #GREEK SMALL LETTER SIGMA
+ 0x00b5, // #MICRO SIGN
+ 0x03c4, // #GREEK SMALL LETTER TAU
+ 0x03a6, // #GREEK CAPITAL LETTER PHI
+ 0x0398, // #GREEK CAPITAL LETTER THETA
+ 0x03a9, // #GREEK CAPITAL LETTER OMEGA
+ 0x03b4, // #GREEK SMALL LETTER DELTA
+ 0x221e, // #INFINITY
+ 0x03c6, // #GREEK SMALL LETTER PHI
+ 0x03b5, // #GREEK SMALL LETTER EPSILON
+ 0x2229, // #INTERSECTION
+ 0x2261, // #IDENTICAL TO
+ 0x00b1, // #PLUS-MINUS SIGN
+ 0x2265, // #GREATER-THAN OR EQUAL TO
+ 0x2264, // #LESS-THAN OR EQUAL TO
+ 0x2320, // #TOP HALF INTEGRAL
+ 0x2321, // #BOTTOM HALF INTEGRAL
+ 0x00f7, // #DIVISION SIGN
+ 0x2248, // #ALMOST EQUAL TO
+ 0x00b0, // #DEGREE SIGN
+ 0x2219, // #BULLET OPERATOR
+ 0x00b7, // #MIDDLE DOT
+ 0x221a, // #SQUARE ROOT
+ 0x207f, // #SUPERSCRIPT LATIN SMALL LETTER N
+ 0x00b2, // #SUPERSCRIPT TWO
+ 0x25a0, // #BLACK SQUARE
+ 0x00a0, // #NO-BREAK SPACE
+ };
+
+ public char map_cp850_unicode(char x) {
+ if (x >= 0x100)
+ return x;
+ return unimap[x];
+ }
+
+ private void _SetCursor(int row, int col) {
+ int maxr = getRows();
+ int tm = getTopMargin();
+
+ R = (row < 0)?0:row;
+ C = (col < 0)?0:col;
+
+ if (!moveoutsidemargins) {
+ R += tm;
+ maxr = getBottomMargin();
+ }
+ if (R > maxr) R = maxr;
+ }
+
+ private void putChar(char c, boolean doshowcursor) {
+ int rows = getRows(); //statusline
+ int columns = getColumns();
+ int tm = getTopMargin();
+ int bm = getBottomMargin();
+ // byte msg[];
+ boolean mapped = false;
+
+ if (debug > 4) System.out.println("putChar(" + c + " [" + ((int) c) + "]) at R=" + R + " , C=" + C + ", columns=" + columns + ", rows=" + rows);
+ markLine(R, 1);
+ if (c > 255) {
+ if (debug > 0)
+ System.out.println("char > 255:" + (int) c);
+ //return;
+ }
+
+
+ switch (term_state) {
+ case TSTATE_DATA:
+ /* FIXME: we shouldn't use chars with bit 8 set if ibmcharset.
+ * probably... but some BBS do anyway...
+ */
+ if (!useibmcharset) {
+ boolean doneflag = true;
+ switch (c) {
+ case OSC:
+ osc = "";
+ term_state = TSTATE_OSC;
+ break;
+ case RI:
+ if (R > tm)
+ R--;
+ else
+ insertLine(R, 1, SCROLL_DOWN);
+ if (debug > 1)
+ System.out.println("RI");
+ break;
+ case IND:
+ if (debug > 2)
+ System.out.println("IND at " + R + ", tm is " + tm + ", bm is " + bm);
+ if (R == bm || R == rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ if (debug > 1)
+ System.out.println("IND (at " + R + " )");
+ break;
+ case NEL:
+ if (R == bm || R == rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ C = 0;
+ if (debug > 1)
+ System.out.println("NEL (at " + R + " )");
+ break;
+ case HTS:
+ Tabs[C] = 1;
+ if (debug > 1)
+ System.out.println("HTS");
+ break;
+ case DCS:
+ dcs = "";
+ term_state = TSTATE_DCS;
+ break;
+ default:
+ doneflag = false;
+ break;
+ }
+ if (doneflag) break;
+ }
+ switch (c) {
+ case SS3:
+ onegl = 3;
+ break;
+ case SS2:
+ onegl = 2;
+ break;
+ case CSI: // should be in the 8bit section, but some BBS use this
+ DCEvar = 0;
+ DCEvars[0] = 0;
+ DCEvars[1] = 0;
+ DCEvars[2] = 0;
+ DCEvars[3] = 0;
+ term_state = TSTATE_CSI;
+ break;
+ case ESC:
+ term_state = TSTATE_ESC;
+ lastwaslf = 0;
+ break;
+ case 5: /* ENQ */
+ write(answerBack, false);
+ break;
+ case 12:
+ /* FormFeed, Home for the BBS world */
+ deleteArea(0, 0, columns, rows, attributes);
+ C = R = 0;
+ break;
+ case '\b': /* 8 */
+ C--;
+ if (C < 0)
+ C = 0;
+ lastwaslf = 0;
+ break;
+ case '\t':
+ do {
+ // Don't overwrite or insert! TABS are not destructive, but movement!
+ C++;
+ } while (C < columns && (Tabs[C] == 0));
+ lastwaslf = 0;
+ break;
+ case '\r':
+ C = 0;
+ break;
+ case '\n':
+ if (debug > 3)
+ System.out.println("R= " + R + ", bm " + bm + ", tm=" + tm + ", rows=" + rows);
+ if (!vms) {
+ if (lastwaslf != 0 && lastwaslf != c) // Ray: I do not understand this logic.
+ break;
+ lastwaslf = c;
+ /*C = 0;*/
+ }
+ if (R == bm || R >= rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ break;
+ case 7:
+ beep();
+ break;
+ case '\016': /* SMACS , as */
+ /* ^N, Shift out - Put G1 into GL */
+ gl = 1;
+ usedcharsets = true;
+ break;
+ case '\017': /* RMACS , ae */
+ /* ^O, Shift in - Put G0 into GL */
+ gl = 0;
+ usedcharsets = true;
+ break;
+ default:
+ {
+ int thisgl = gl;
+
+ if (onegl >= 0) {
+ thisgl = onegl;
+ onegl = -1;
+ }
+ lastwaslf = 0;
+ if (c < 32) {
+ if (c != 0)
+ if (debug > 0)
+ System.out.println("TSTATE_DATA char: " + ((int) c));
+ /*break; some BBS really want those characters, like hearst etc. */
+ if (c == 0) /* print 0 ... you bet */
+ break;
+ }
+ if (C >= columns) {
+ if (wraparound) {
+ if (R < rows - 1)
+ R++;
+ else
+ insertLine(R, 1, SCROLL_UP);
+ C = 0;
+ } else {
+ // cursor stays on last character.
+ C = columns - 1;
+ }
+ }
+
+ // Mapping if DEC Special is chosen charset
+ if (usedcharsets) {
+ if (c >= '\u0020' && c <= '\u007f') {
+ switch (gx[thisgl]) {
+ case '0':
+ // Remap SCOANSI line drawing to VT100 line drawing chars
+ // for our SCO using customers.
+ if (terminalID.equals("scoansi") || terminalID.equals("ansi")) {
+ for (int i = 0; i < scoansi_acs.length(); i += 2) {
+ if (c == scoansi_acs.charAt(i)) {
+ c = scoansi_acs.charAt(i + 1);
+ break;
+ }
+ }
+ }
+ if (c >= '\u005f' && c <= '\u007e') {
+ c = DECSPECIAL[(short) c - 0x5f];
+ mapped = true;
+ }
+ break;
+ case '<': // 'user preferred' is currently 'ISO Latin-1 suppl
+ c = (char) (((int) c & 0x7f) | 0x80);
+ mapped = true;
+ break;
+ case 'A':
+ case 'B': // Latin-1 , ASCII -> fall through
+ mapped = true;
+ break;
+ default:
+ System.out.println("Unsupported GL mapping: " + gx[thisgl]);
+ break;
+ }
+ }
+ if (!mapped && (c >= '\u0080' && c <= '\u00ff')) {
+ switch (gx[gr]) {
+ case '0':
+ if (c >= '\u00df' && c <= '\u00fe') {
+ c = DECSPECIAL[c - '\u00df'];
+ mapped = true;
+ }
+ break;
+ case '<':
+ case 'A':
+ case 'B':
+ mapped = true;
+ break;
+ default:
+ System.out.println("Unsupported GR mapping: " + gx[gr]);
+ break;
+ }
+ }
+ }
+ if (!mapped && useibmcharset)
+ c = map_cp850_unicode(c);
+
+ /*if(true || (statusmode == 0)) { */
+ if (insertmode == 1) {
+ insertChar(C, R, c, attributes);
+ } else {
+ putChar(C, R, c, attributes);
+ }
+ /*
+ } else {
+ if (insertmode==1) {
+ insertChar(C, rows, c, attributes);
+ } else {
+ putChar(C, rows, c, attributes);
+ }
+ }
+ */
+ C++;
+ break;
+ }
+ } /* switch(c) */
+ break;
+ case TSTATE_OSC:
+ if ((c < 0x20) && (c != ESC)) {// NP - No printing character
+ handle_osc(osc);
+ term_state = TSTATE_DATA;
+ break;
+ }
+ //but check for vt102 ESC \
+ if (c == '\\' && osc.charAt(osc.length() - 1) == ESC) {
+ handle_osc(osc);
+ term_state = TSTATE_DATA;
+ break;
+ }
+ osc = osc + c;
+ break;
+ case TSTATE_ESCSPACE:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case 'F': /* S7C1T, Disable output of 8-bit controls, use 7-bit */
+ output8bit = false;
+ break;
+ case 'G': /* S8C1T, Enable output of 8-bit control codes*/
+ output8bit = true;
+ break;
+ default:
+ System.out.println("ESC <space> " + c + " unhandled.");
+ }
+ break;
+ case TSTATE_ESC:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case ' ':
+ term_state = TSTATE_ESCSPACE;
+ break;
+ case '#':
+ term_state = TSTATE_ESCSQUARE;
+ break;
+ case 'c':
+ /* Hard terminal reset */
+ /* reset character sets */
+ gx[0] = 'B';
+ gx[1] = '0';
+ gx[2] = 'B';
+ gx[3] = 'B';
+ gl = 0; // default GL to G0
+ gr = 1; // default GR to G1
+ /* reset tabs */
+ int nw = getColumns();
+ if (nw < 132) nw = 132;
+ Tabs = new byte[nw];
+ for (int i = 0; i < nw; i += 8) {
+ Tabs[i] = 1;
+ }
+ /*FIXME:*/
+ break;
+ case '[':
+ DCEvar = 0;
+ DCEvars[0] = 0;
+ DCEvars[1] = 0;
+ DCEvars[2] = 0;
+ DCEvars[3] = 0;
+ term_state = TSTATE_CSI;
+ break;
+ case ']':
+ osc = "";
+ term_state = TSTATE_OSC;
+ break;
+ case 'P':
+ dcs = "";
+ term_state = TSTATE_DCS;
+ break;
+ case 'A': /* CUU */
+ R--;
+ if (R < 0) R = 0;
+ break;
+ case 'B': /* CUD */
+ R++;
+ if (R > rows - 1) R = rows - 1;
+ break;
+ case 'C':
+ C++;
+ if (C >= columns) C = columns - 1;
+ break;
+ case 'I': // RI
+ insertLine(R, 1, SCROLL_DOWN);
+ break;
+ case 'E': /* NEL */
+ if (R == bm || R == rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ C = 0;
+ if (debug > 1)
+ System.out.println("ESC E (at " + R + ")");
+ break;
+ case 'D': /* IND */
+ if (R == bm || R == rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ if (debug > 1)
+ System.out.println("ESC D (at " + R + " )");
+ break;
+ case 'J': /* erase to end of screen */
+ if (R < rows - 1)
+ deleteArea(0, R + 1, columns, rows - R - 1, attributes);
+ if (C < columns - 1)
+ deleteArea(C, R, columns - C, 1, attributes);
+ break;
+ case 'K':
+ if (C < columns - 1)
+ deleteArea(C, R, columns - C, 1, attributes);
+ break;
+ case 'M': // RI
+ System.out.println("ESC M : R is "+R+", tm is "+tm+", bm is "+bm);
+ if (R > bm) // outside scrolling region
+ break;
+ if (R > tm) { // just go up 1 line.
+ R--;
+ } else { // scroll down
+ insertLine(R, 1, SCROLL_DOWN);
+ }
+ /* else do nothing ; */
+ if (debug > 2)
+ System.out.println("ESC M ");
+ break;
+ case 'H':
+ if (debug > 1)
+ System.out.println("ESC H at " + C);
+ /* right border probably ...*/
+ if (C >= columns)
+ C = columns - 1;
+ Tabs[C] = 1;
+ break;
+ case 'N': // SS2
+ onegl = 2;
+ break;
+ case 'O': // SS3
+ onegl = 3;
+ break;
+ case '=':
+ /*application keypad*/
+ if (debug > 0)
+ System.out.println("ESC =");
+ keypadmode = true;
+ break;
+ case '<': /* vt52 mode off */
+ vt52mode = false;
+ break;
+ case '>': /*normal keypad*/
+ if (debug > 0)
+ System.out.println("ESC >");
+ keypadmode = false;
+ break;
+ case '7': /*save cursor, attributes, margins */
+ Sc = C;
+ Sr = R;
+ Sgl = gl;
+ Sgr = gr;
+ Sa = attributes;
+ Sgx = new char[4];
+ for (int i = 0; i < 4; i++) Sgx[i] = gx[i];
+ Stm = getTopMargin();
+ Sbm = getBottomMargin();
+ if (debug > 1)
+ System.out.println("ESC 7");
+ break;
+ case '8': /*restore cursor, attributes, margins */
+ C = Sc;
+ R = Sr;
+ gl = Sgl;
+ gr = Sgr;
+ for (int i = 0; i < 4; i++) gx[i] = Sgx[i];
+ setTopMargin(Stm);
+ setBottomMargin(Sbm);
+ attributes = Sa;
+ if (debug > 1)
+ System.out.println("ESC 8");
+ break;
+ case '(': /* Designate G0 Character set (ISO 2022) */
+ term_state = TSTATE_SETG0;
+ usedcharsets = true;
+ break;
+ case ')': /* Designate G1 character set (ISO 2022) */
+ term_state = TSTATE_SETG1;
+ usedcharsets = true;
+ break;
+ case '*': /* Designate G2 Character set (ISO 2022) */
+ term_state = TSTATE_SETG2;
+ usedcharsets = true;
+ break;
+ case '+': /* Designate G3 Character set (ISO 2022) */
+ term_state = TSTATE_SETG3;
+ usedcharsets = true;
+ break;
+ case '~': /* Locking Shift 1, right */
+ gr = 1;
+ usedcharsets = true;
+ break;
+ case 'n': /* Locking Shift 2 */
+ gl = 2;
+ usedcharsets = true;
+ break;
+ case '}': /* Locking Shift 2, right */
+ gr = 2;
+ usedcharsets = true;
+ break;
+ case 'o': /* Locking Shift 3 */
+ gl = 3;
+ usedcharsets = true;
+ break;
+ case '|': /* Locking Shift 3, right */
+ gr = 3;
+ usedcharsets = true;
+ break;
+ case 'Y': /* vt52 cursor address mode , next chars are x,y */
+ term_state = TSTATE_VT52Y;
+ break;
+ default:
+ System.out.println("ESC unknown letter: " + c + " (" + ((int) c) + ")");
+ break;
+ }
+ break;
+ case TSTATE_VT52X:
+ C = c - 37;
+ term_state = TSTATE_VT52Y;
+ break;
+ case TSTATE_VT52Y:
+ R = c - 37;
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_SETG0:
+ if (c != '0' && c != 'A' && c != 'B' && c != '<')
+ System.out.println("ESC ( " + c + ": G0 char set? (" + ((int) c) + ")");
+ else {
+ if (debug > 2) System.out.println("ESC ( : G0 char set (" + c + " " + ((int) c) + ")");
+ gx[0] = c;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_SETG1:
+ if (c != '0' && c != 'A' && c != 'B' && c != '<') {
+ System.out.println("ESC ) " + c + " (" + ((int) c) + ") :G1 char set?");
+ } else {
+ if (debug > 2) System.out.println("ESC ) :G1 char set (" + c + " " + ((int) c) + ")");
+ gx[1] = c;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_SETG2:
+ if (c != '0' && c != 'A' && c != 'B' && c != '<')
+ System.out.println("ESC*:G2 char set? (" + ((int) c) + ")");
+ else {
+ if (debug > 2) System.out.println("ESC*:G2 char set (" + c + " " + ((int) c) + ")");
+ gx[2] = c;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_SETG3:
+ if (c != '0' && c != 'A' && c != 'B' && c != '<')
+ System.out.println("ESC+:G3 char set? (" + ((int) c) + ")");
+ else {
+ if (debug > 2) System.out.println("ESC+:G3 char set (" + c + " " + ((int) c) + ")");
+ gx[3] = c;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_ESCSQUARE:
+ switch (c) {
+ case '8':
+ for (int i = 0; i < columns; i++)
+ for (int j = 0; j < rows; j++)
+ putChar(i, j, 'E', 0);
+ break;
+ default:
+ System.out.println("ESC # " + c + " not supported.");
+ break;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_DCS:
+ if (c == '\\' && dcs.charAt(dcs.length() - 1) == ESC) {
+ handle_dcs(dcs);
+ term_state = TSTATE_DATA;
+ break;
+ }
+ dcs = dcs + c;
+ break;
+
+ case TSTATE_DCEQ:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + ((int) c) - 48;
+ term_state = TSTATE_DCEQ;
+ break;
+ case ';':
+ DCEvar++;
+ DCEvars[DCEvar] = 0;
+ term_state = TSTATE_DCEQ;
+ break;
+ case 's': // XTERM_SAVE missing!
+ if (true || debug > 1)
+ System.out.println("ESC [ ? " + DCEvars[0] + " s unimplemented!");
+ break;
+ case 'r': // XTERM_RESTORE
+ if (true || debug > 1)
+ System.out.println("ESC [ ? " + DCEvars[0] + " r");
+ /* DEC Mode reset */
+ for (int i = 0; i <= DCEvar; i++) {
+ switch (DCEvars[i]) {
+ case 3: /* 80 columns*/
+ setScreenSize(80, getRows(), true);
+ break;
+ case 4: /* scrolling mode, smooth */
+ break;
+ case 5: /* light background */
+ break;
+ case 6: /* DECOM (Origin Mode) move inside margins. */
+ moveoutsidemargins = true;
+ break;
+ case 7: /* DECAWM: Autowrap Mode */
+ wraparound = false;
+ break;
+ case 12:/* local echo off */
+ break;
+ case 9: /* X10 mouse */
+ case 1000: /* xterm style mouse report on */
+ case 1001:
+ case 1002:
+ case 1003:
+ mouserpt = DCEvars[i];
+ break;
+ default:
+ System.out.println("ESC [ ? " + DCEvars[0] + " r, unimplemented!");
+ }
+ }
+ break;
+ case 'h': // DECSET
+ if (debug > 0)
+ System.out.println("ESC [ ? " + DCEvars[0] + " h");
+ /* DEC Mode set */
+ for (int i = 0; i <= DCEvar; i++) {
+ switch (DCEvars[i]) {
+ case 1: /* Application cursor keys */
+ KeyUp[0] = "\u001bOA";
+ KeyDown[0] = "\u001bOB";
+ KeyRight[0] = "\u001bOC";
+ KeyLeft[0] = "\u001bOD";
+ break;
+ case 2: /* DECANM */
+ vt52mode = false;
+ break;
+ case 3: /* 132 columns*/
+ setScreenSize(132, getRows(), true);
+ break;
+ case 6: /* DECOM: move inside margins. */
+ moveoutsidemargins = false;
+ break;
+ case 7: /* DECAWM: Autowrap Mode */
+ wraparound = true;
+ break;
+ case 25: /* turn cursor on */
+ showCursor(true);
+ break;
+ case 9: /* X10 mouse */
+ case 1000: /* xterm style mouse report on */
+ case 1001:
+ case 1002:
+ case 1003:
+ mouserpt = DCEvars[i];
+ break;
+
+ /* unimplemented stuff, fall through */
+ /* 4 - scrolling mode, smooth */
+ /* 5 - light background */
+ /* 12 - local echo off */
+ /* 18 - DECPFF - Printer Form Feed Mode -> On */
+ /* 19 - DECPEX - Printer Extent Mode -> Screen */
+ default:
+ System.out.println("ESC [ ? " + DCEvars[0] + " h, unsupported.");
+ break;
+ }
+ }
+ break;
+ case 'i': // DEC Printer Control, autoprint, echo screenchars to printer
+ // This is different to CSI i!
+ // Also: "Autoprint prints a final display line only when the
+ // cursor is moved off the line by an autowrap or LF, FF, or
+ // VT (otherwise do not print the line)."
+ switch (DCEvars[0]) {
+ case 1:
+ if (debug > 1)
+ System.out.println("CSI ? 1 i : Print line containing cursor");
+ break;
+ case 4:
+ if (debug > 1)
+ System.out.println("CSI ? 4 i : Start passthrough printing");
+ break;
+ case 5:
+ if (debug > 1)
+ System.out.println("CSI ? 4 i : Stop passthrough printing");
+ break;
+ }
+ break;
+ case 'l': //DECRST
+ /* DEC Mode reset */
+ if (debug > 0)
+ System.out.println("ESC [ ? " + DCEvars[0] + " l");
+ for (int i = 0; i <= DCEvar; i++) {
+ switch (DCEvars[i]) {
+ case 1: /* Application cursor keys */
+ KeyUp[0] = "\u001b[A";
+ KeyDown[0] = "\u001b[B";
+ KeyRight[0] = "\u001b[C";
+ KeyLeft[0] = "\u001b[D";
+ break;
+ case 2: /* DECANM */
+ vt52mode = true;
+ break;
+ case 3: /* 80 columns*/
+ setScreenSize(80, getRows(), true);
+ break;
+ case 6: /* DECOM: move outside margins. */
+ moveoutsidemargins = true;
+ break;
+ case 7: /* DECAWM: Autowrap Mode OFF */
+ wraparound = false;
+ break;
+ case 25: /* turn cursor off */
+ showCursor(false);
+ break;
+ /* Unimplemented stuff: */
+ /* 4 - scrolling mode, jump */
+ /* 5 - dark background */
+ /* 7 - DECAWM - no wrap around mode */
+ /* 12 - local echo on */
+ /* 18 - DECPFF - Printer Form Feed Mode -> Off*/
+ /* 19 - DECPEX - Printer Extent Mode -> Scrolling Region */
+ case 9: /* X10 mouse */
+ case 1000: /* xterm style mouse report OFF */
+ case 1001:
+ case 1002:
+ case 1003:
+ mouserpt = 0;
+ break;
+ default:
+ System.out.println("ESC [ ? " + DCEvars[0] + " l, unsupported.");
+ break;
+ }
+ }
+ break;
+ case 'n':
+ if (debug > 0)
+ System.out.println("ESC [ ? " + DCEvars[0] + " n");
+ switch (DCEvars[0]) {
+ case 15:
+ /* printer? no printer. */
+ write(((char) ESC) + "[?13n", false);
+ System.out.println("ESC[5n");
+ break;
+ default:
+ System.out.println("ESC [ ? " + DCEvars[0] + " n, unsupported.");
+ break;
+ }
+ break;
+ default:
+ System.out.println("ESC [ ? " + DCEvars[0] + " " + c + ", unsupported.");
+ break;
+ }
+ break;
+ case TSTATE_CSI_EX:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case ESC:
+ term_state = TSTATE_ESC;
+ break;
+ default:
+ System.out.println("Unknown character ESC[! character is " + (int) c);
+ break;
+ }
+ break;
+ case TSTATE_CSI_TICKS:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case 'p':
+ System.out.println("Conformance level: " + DCEvars[0] + " (unsupported)," + DCEvars[1]);
+ if (DCEvars[0] == 61) {
+ output8bit = false;
+ break;
+ }
+ if (DCEvars[1] == 1) {
+ output8bit = false;
+ } else {
+ output8bit = true; /* 0 or 2 */
+ }
+ break;
+ default:
+ System.out.println("Unknown ESC [... \"" + c);
+ break;
+ }
+ break;
+ case TSTATE_CSI_EQUAL:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + ((int) c) - 48;
+ term_state = TSTATE_CSI_EQUAL;
+ break;
+ case ';':
+ DCEvar++;
+ DCEvars[DCEvar] = 0;
+ term_state = TSTATE_CSI_EQUAL;
+ break;
+
+ case 'F': /* SCO ANSI foreground */
+ {
+ int newcolor;
+
+ System.out.println("ESC [ = "+DCEvars[0]+" F");
+
+ attributes &= ~COLOR_FG;
+ newcolor = ((DCEvars[0] & 1) << 2) |
+ (DCEvars[0] & 2) |
+ ((DCEvars[0] & 4) >> 2) ;
+ attributes |= (newcolor+1) << COLOR_FG_SHIFT;
+
+ break;
+ }
+ case 'G': /* SCO ANSI background */
+ {
+ int newcolor;
+
+ System.out.println("ESC [ = "+DCEvars[0]+" G");
+
+ attributes &= ~COLOR_BG;
+ newcolor = ((DCEvars[0] & 1) << 2) |
+ (DCEvars[0] & 2) |
+ ((DCEvars[0] & 4) >> 2) ;
+ attributes |= (newcolor+1) << COLOR_BG_SHIFT;
+ break;
+ }
+
+ default:
+ System.out.print("Unknown ESC [ = ");
+ for (int i=0;i<=DCEvar;i++)
+ System.out.print(DCEvars[i]+",");
+ System.out.println("" + c);
+ break;
+ }
+ break;
+ case TSTATE_CSI_DOLLAR:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case '}':
+ System.out.println("Active Status Display now " + DCEvars[0]);
+ statusmode = DCEvars[0];
+ break;
+ /* bad documentation?
+ case '-':
+ System.out.println("Set Status Display now "+DCEvars[0]);
+ break;
+ */
+ case '~':
+ System.out.println("Status Line mode now " + DCEvars[0]);
+ break;
+ default:
+ System.out.println("UNKNOWN Status Display code " + c + ", with Pn=" + DCEvars[0]);
+ break;
+ }
+ break;
+ case TSTATE_CSI:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case '"':
+ term_state = TSTATE_CSI_TICKS;
+ break;
+ case '$':
+ term_state = TSTATE_CSI_DOLLAR;
+ break;
+ case '=':
+ term_state = TSTATE_CSI_EQUAL;
+ break;
+ case '!':
+ term_state = TSTATE_CSI_EX;
+ break;
+ case '?':
+ DCEvar = 0;
+ DCEvars[0] = 0;
+ term_state = TSTATE_DCEQ;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + ((int) c) - 48;
+ term_state = TSTATE_CSI;
+ break;
+ case ';':
+ DCEvar++;
+ DCEvars[DCEvar] = 0;
+ term_state = TSTATE_CSI;
+ break;
+ case 'c':/* send primary device attributes */
+ /* send (ESC[?61c) */
+
+ String subcode = "";
+ if (terminalID.equals("vt320")) subcode = "63;";
+ if (terminalID.equals("vt220")) subcode = "62;";
+ if (terminalID.equals("vt100")) subcode = "61;";
+ write(((char) ESC) + "[?" + subcode + "1;2c", false);
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " c");
+ break;
+ case 'q':
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " q");
+ break;
+ case 'g':
+ /* used for tabsets */
+ switch (DCEvars[0]) {
+ case 3:/* clear them */
+ Tabs = new byte[getColumns()];
+ break;
+ case 0:
+ Tabs[C] = 0;
+ break;
+ }
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " g");
+ break;
+ case 'h':
+ switch (DCEvars[0]) {
+ case 4:
+ insertmode = 1;
+ break;
+ case 20:
+ System.out.println("Setting CRLF to TRUE");
+ sendcrlf = true;
+ break;
+ default:
+ System.out.println("unsupported: ESC [ " + DCEvars[0] + " h");
+ break;
+ }
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " h");
+ break;
+ case 'i': // Printer Controller mode.
+ // "Transparent printing sends all output, except the CSI 4 i
+ // termination string, to the printer and not the screen,
+ // uses an 8-bit channel if no parity so NUL and DEL will be
+ // seen by the printer and by the termination recognizer code,
+ // and all translation and character set selections are
+ // bypassed."
+ switch (DCEvars[0]) {
+ case 0:
+ if (debug > 1)
+ System.out.println("CSI 0 i: Print Screen, not implemented.");
+ break;
+ case 4:
+ if (debug > 1)
+ System.out.println("CSI 4 i: Enable Transparent Printing, not implemented.");
+ break;
+ case 5:
+ if (debug > 1)
+ System.out.println("CSI 4/5 i: Disable Transparent Printing, not implemented.");
+ break;
+ default:
+ System.out.println("ESC [ " + DCEvars[0] + " i, unimplemented!");
+ }
+ break;
+ case 'l':
+ switch (DCEvars[0]) {
+ case 4:
+ insertmode = 0;
+ break;
+ case 20:
+ System.out.println("Setting CRLF to FALSE");
+ sendcrlf = false;
+ break;
+ default:
+ System.out.println("ESC [ " + DCEvars[0] + " l, unimplemented!");
+ break;
+ }
+ break;
+ case 'A': // CUU
+ {
+ int limit;
+ /* FIXME: xterm only cares about 0 and topmargin */
+ if (R > bm)
+ limit = bm + 1;
+ else if (R >= tm) {
+ limit = tm;
+ } else
+ limit = 0;
+ if (DCEvars[0] == 0)
+ R--;
+ else
+ R -= DCEvars[0];
+ if (R < limit)
+ R = limit;
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " A");
+ break;
+ }
+ case 'B': // CUD
+ /* cursor down n (1) times */
+ {
+ int limit;
+ if (R < tm)
+ limit = tm - 1;
+ else if (R <= bm) {
+ limit = bm;
+ } else
+ limit = rows - 1;
+ if (DCEvars[0] == 0)
+ R++;
+ else
+ R += DCEvars[0];
+ if (R > limit)
+ R = limit;
+ else {
+ if (debug > 2) System.out.println("Not limited.");
+ }
+ if (debug > 2) System.out.println("to: " + R);
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " B (at C=" + C + ")");
+ break;
+ }
+ case 'C':
+ if (DCEvars[0] == 0)
+ C++;
+ else
+ C += DCEvars[0];
+ if (C > columns - 1)
+ C = columns - 1;
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " C");
+ break;
+ case 'd': // CVA
+ R = DCEvars[0];
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " d");
+ break;
+ case 'D':
+ if (DCEvars[0] == 0)
+ C--;
+ else
+ C -= DCEvars[0];
+ if (C < 0) C = 0;
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " D");
+ break;
+ case 'r': // DECSTBM
+ if (DCEvar > 0) // Ray: Any argument is optional
+ {
+ R = DCEvars[1] - 1;
+ if (R < 0)
+ R = rows - 1;
+ else if (R >= rows) {
+ R = rows - 1;
+ }
+ } else
+ R = rows - 1;
+ setBottomMargin(R);
+ if (R >= DCEvars[0]) {
+ R = DCEvars[0] - 1;
+ if (R < 0)
+ R = 0;
+ }
+ setTopMargin(R);
+ _SetCursor(0, 0);
+ if (debug > 1)
+ System.out.println("ESC [" + DCEvars[0] + " ; " + DCEvars[1] + " r");
+ break;
+ case 'G': /* CUP / cursor absolute column */
+ C = DCEvars[0];
+ if (debug > 1) System.out.println("ESC [ " + DCEvars[0] + " G");
+ break;
+ case 'H': /* CUP / cursor position */
+ /* gets 2 arguments */
+ _SetCursor(DCEvars[0] - 1, DCEvars[1] - 1);
+ if (debug > 2) {
+ System.out.println("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " H, moveoutsidemargins " + moveoutsidemargins);
+ System.out.println(" -> R now " + R + ", C now " + C);
+ }
+ break;
+ case 'f': /* move cursor 2 */
+ /* gets 2 arguments */
+ R = DCEvars[0] - 1;
+ C = DCEvars[1] - 1;
+ if (C < 0) C = 0;
+ if (R < 0) R = 0;
+ if (debug > 2)
+ System.out.println("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " f");
+ break;
+ case 'S': /* ind aka 'scroll forward' */
+ if (DCEvars[0] == 0)
+ insertLine(rows - 1, SCROLL_UP);
+ else
+ insertLine(rows - 1, DCEvars[0], SCROLL_UP);
+ break;
+ case 'L':
+ /* insert n lines */
+ if (DCEvars[0] == 0)
+ insertLine(R, SCROLL_DOWN);
+ else
+ insertLine(R, DCEvars[0], SCROLL_DOWN);
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + "" + (c) + " (at R " + R + ")");
+ break;
+ case 'T': /* 'ri' aka scroll backward */
+ if (DCEvars[0] == 0)
+ insertLine(0, SCROLL_DOWN);
+ else
+ insertLine(0, DCEvars[0], SCROLL_DOWN);
+ break;
+ case 'M':
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + "" + (c) + " at R=" + R);
+ if (DCEvars[0] == 0)
+ deleteLine(R);
+ else
+ for (int i = 0; i < DCEvars[0]; i++)
+ deleteLine(R);
+ break;
+ case 'K':
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " K");
+ /* clear in line */
+ switch (DCEvars[0]) {
+ case 6: /* 97801 uses ESC[6K for delete to end of line */
+ case 0:/*clear to right*/
+ if (C < columns - 1)
+ deleteArea(C, R, columns - C, 1, attributes);
+ break;
+ case 1:/*clear to the left, including this */
+ if (C > 0)
+ deleteArea(0, R, C + 1, 1, attributes);
+ break;
+ case 2:/*clear whole line */
+ deleteArea(0, R, columns, 1, attributes);
+ break;
+ }
+ break;
+ case 'J':
+ /* clear below current line */
+ switch (DCEvars[0]) {
+ case 0:
+ if (R < rows - 1)
+ deleteArea(0, R + 1, columns, rows - R - 1, attributes);
+ if (C < columns - 1)
+ deleteArea(C, R, columns - C, 1, attributes);
+ break;
+ case 1:
+ if (R > 0)
+ deleteArea(0, 0, columns, R, attributes);
+ if (C > 0)
+ deleteArea(0, R, C + 1, 1, attributes);// include up to and including current
+ break;
+ case 2:
+ deleteArea(0, 0, columns, rows, attributes);
+ break;
+ }
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " J");
+ break;
+ case '@':
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " @");
+ for (int i = 0; i < DCEvars[0]; i++)
+ insertChar(C, R, ' ', attributes);
+ break;
+ case 'X':
+ {
+ int toerase = DCEvars[0];
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " X, C=" + C + ",R=" + R);
+ if (toerase == 0)
+ toerase = 1;
+ if (toerase + C > columns)
+ toerase = columns - C;
+ deleteArea(C, R, toerase, 1, attributes);
+ // does not change cursor position
+ break;
+ }
+ case 'P':
+ if (debug > 1)
+ System.out.println("ESC [ " + DCEvars[0] + " P, C=" + C + ",R=" + R);
+ if (DCEvars[0] == 0) DCEvars[0] = 1;
+ for (int i = 0; i < DCEvars[0]; i++)
+ deleteChar(C, R);
+ break;
+ case 'n':
+ switch (DCEvars[0]) {
+ case 5: /* malfunction? No malfunction. */
+ writeSpecial(((char) ESC) + "[0n");
+ if (debug > 1)
+ System.out.println("ESC[5n");
+ break;
+ case 6:
+ // DO NOT offset R and C by 1! (checked against /usr/X11R6/bin/resize
+ // FIXME check again.
+ // FIXME: but vttest thinks different???
+ writeSpecial(((char) ESC) + "[" + R + ";" + C + "R");
+ if (debug > 1)
+ System.out.println("ESC[6n");
+ break;
+ default:
+ if (debug > 0)
+ System.out.println("ESC [ " + DCEvars[0] + " n??");
+ break;
+ }
+ break;
+ case 's': /* DECSC - save cursor */
+ Sc = C;
+ Sr = R;
+ Sa = attributes;
+ if (debug > 3)
+ System.out.println("ESC[s");
+ break;
+ case 'u': /* DECRC - restore cursor */
+ C = Sc;
+ R = Sr;
+ attributes = Sa;
+ if (debug > 3)
+ System.out.println("ESC[u");
+ break;
+ case 'm': /* attributes as color, bold , blink,*/
+ if (debug > 3)
+ System.out.print("ESC [ ");
+ if (DCEvar == 0 && DCEvars[0] == 0)
+ attributes = 0;
+ for (int i = 0; i <= DCEvar; i++) {
+ switch (DCEvars[i]) {
+ case 0:
+ if (DCEvar > 0) {
+ if (terminalID.equals("scoansi")) {
+ attributes &= COLOR; /* Keeps color. Strange but true. */
+ } else {
+ attributes = 0;
+ }
+ }
+ break;
+ case 1:
+ attributes |= BOLD;
+ attributes &= ~LOW;
+ break;
+ case 2:
+ /* SCO color hack mode */
+ if (terminalID.equals("scoansi") && ((DCEvar - i) >= 2)) {
+ int ncolor;
+ attributes &= ~(COLOR | BOLD);
+
+ ncolor = DCEvars[i + 1];
+ if ((ncolor & 8) == 8)
+ attributes |= BOLD;
+ ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
+ attributes |= ((ncolor) + 1) << COLOR_FG_SHIFT;
+ ncolor = DCEvars[i + 2];
+ ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
+ attributes |= ((ncolor) + 1) << COLOR_BG_SHIFT;
+ i += 2;
+ } else {
+ attributes |= LOW;
+ }
+ break;
+ case 4:
+ attributes |= UNDERLINE;
+ break;
+ case 7:
+ attributes |= INVERT;
+ break;
+ case 8:
+ attributes |= INVISIBLE;
+ break;
+ case 5: /* blink on */
+ break;
+ /* 10 - ANSI X3.64-1979, select primary font, don't display control
+ * chars, don't set bit 8 on output */
+ case 10:
+ gl = 0;
+ usedcharsets = true;
+ break;
+ /* 11 - ANSI X3.64-1979, select second alt. font, display control
+ * chars, set bit 8 on output */
+ case 11: /* SMACS , as */
+ case 12:
+ gl = 1;
+ usedcharsets = true;
+ break;
+ case 21: /* normal intensity */
+ attributes &= ~(LOW | BOLD);
+ break;
+ case 25: /* blinking off */
+ break;
+ case 27:
+ attributes &= ~INVERT;
+ break;
+ case 28:
+ attributes &= ~INVISIBLE;
+ break;
+ case 24:
+ attributes &= ~UNDERLINE;
+ break;
+ case 22:
+ attributes &= ~BOLD;
+ break;
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ attributes &= ~COLOR_FG;
+ attributes |= ((DCEvars[i] - 30) + 1) << COLOR_FG_SHIFT;
+ break;
+ case 39:
+ attributes &= ~COLOR_FG;
+ break;
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ attributes &= ~COLOR_BG;
+ attributes |= ((DCEvars[i] - 40) + 1) << COLOR_BG_SHIFT;
+ break;
+ case 49:
+ attributes &= ~COLOR_BG;
+ break;
+
+ default:
+ System.out.println("ESC [ " + DCEvars[i] + " m unknown...");
+ break;
+ }
+ if (debug > 3)
+ System.out.print("" + DCEvars[i] + ";");
+ }
+ if (debug > 3)
+ System.out.print(" (attributes = " + attributes + ")m \n");
+ break;
+ default:
+ System.out.println("ESC [ unknown letter:" + c + " (" + ((int) c) + ")");
+ break;
+ }
+ break;
+ default:
+ term_state = TSTATE_DATA;
+ break;
+ }
+ if (C > columns) C = columns;
+ if (R > rows) R = rows;
+ if (C < 0) C = 0;
+ if (R < 0) R = 0;
+ if (doshowcursor)
+ setCursorPosition(C, R);
+ markLine(R, 1);
+ }
+
+ /* hard reset the terminal */
+ public void reset() {
+ gx[0] = 'B';
+ gx[1] = '0';
+ gx[2] = 'B';
+ gx[3] = 'B';
+ gl = 0; // default GL to G0
+ gr = 1; // default GR to G1
+ /* reset tabs */
+ int nw = getColumns();
+ if (nw < 132) nw = 132;
+ Tabs = new byte[nw];
+ for (int i = 0; i < nw; i += 8) {
+ Tabs[i] = 1;
+ }
+ /*FIXME:*/
+ term_state = TSTATE_DATA;
+ }
+}
diff --git a/src/org/theb/provider/HostDb.java b/src/org/theb/provider/HostDb.java
index 3bed790..e38396c 100644
--- a/src/org/theb/provider/HostDb.java
+++ b/src/org/theb/provider/HostDb.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
package org.theb.provider;
import android.net.ContentURI;
diff --git a/src/org/theb/ssh/ConnectionThread.java b/src/org/theb/ssh/ConnectionThread.java
new file mode 100644
index 0000000..a201e62
--- /dev/null
+++ b/src/org/theb/ssh/ConnectionThread.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.theb.ssh;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public abstract class ConnectionThread extends Thread {
+ public ConnectionThread(FeedbackUI ui, String hostname, String username, int port) {}
+ public abstract void finish();
+ public abstract InputStream getReader();
+ public abstract OutputStream getWriter();
+ public abstract void setPassword(String password);
+}
diff --git a/src/org/theb/ssh/FeedbackUI.java b/src/org/theb/ssh/FeedbackUI.java
new file mode 100644
index 0000000..ba4ae03
--- /dev/null
+++ b/src/org/theb/ssh/FeedbackUI.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.theb.ssh;
+
+public interface FeedbackUI {
+ public void connectionLost(Throwable reason);
+ public void setWaiting(boolean isWaiting, String title, String message);
+ public void askPassword();
+}
diff --git a/src/org/theb/ssh/HostDbProvider.java b/src/org/theb/ssh/HostDbProvider.java
index 20ec224..f0eac73 100644
--- a/src/org/theb/ssh/HostDbProvider.java
+++ b/src/org/theb/ssh/HostDbProvider.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
package org.theb.ssh;
import java.util.HashMap;
diff --git a/src/org/theb/ssh/HostEditor.java b/src/org/theb/ssh/HostEditor.java
index d642fd4..967cf5b 100644
--- a/src/org/theb/ssh/HostEditor.java
+++ b/src/org/theb/ssh/HostEditor.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
package org.theb.ssh;
import org.theb.provider.HostDb;
diff --git a/src/org/theb/ssh/HostsList.java b/src/org/theb/ssh/HostsList.java
index 4d9e398..7114497 100644
--- a/src/org/theb/ssh/HostsList.java
+++ b/src/org/theb/ssh/HostsList.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
package org.theb.ssh;
import org.theb.provider.HostDb;
diff --git a/src/org/theb/ssh/InteractiveHostKeyVerifier.java b/src/org/theb/ssh/InteractiveHostKeyVerifier.java
index a461724..7c21f80 100644
--- a/src/org/theb/ssh/InteractiveHostKeyVerifier.java
+++ b/src/org/theb/ssh/InteractiveHostKeyVerifier.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
package org.theb.ssh;
import com.trilead.ssh2.ServerHostKeyVerifier;
diff --git a/src/org/theb/ssh/JCTerminalView.java b/src/org/theb/ssh/JCTerminalView.java
new file mode 100644
index 0000000..47d12aa
--- /dev/null
+++ b/src/org/theb/ssh/JCTerminalView.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.theb.ssh;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PixelXorXfermode;
+import android.graphics.Typeface;
+import android.graphics.Paint.FontMetricsInt;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.jcraft.jcterm.Emulator;
+import com.jcraft.jcterm.EmulatorVT100;
+import com.jcraft.jcterm.Term;
+
+public class JCTerminalView extends View implements Term, Terminal {
+ private final Paint mPaint;
+ private Bitmap mBitmap;
+ private Canvas mCanvas;
+
+ private final Paint mCursorPaint;
+
+ private Emulator emulator = null;
+
+ private boolean mBold = false;
+ private boolean mUnderline = false;
+ private boolean mReverse = false;
+
+ private int mDefaultForeground = Color.WHITE;
+ private int mDefaultBackground = Color.BLACK;
+ private int mForeground = Color.WHITE;
+ private int mBackground = Color.BLACK;
+
+ private boolean mAntialias = true;
+
+ private int mTermWidth = 80;
+ private int mTermHeight = 24;
+
+ private int mCharHeight;
+ private int mCharWidth;
+ private int mDescent;
+
+
+ // Cursor location
+ private int x = 0;
+ private int y = 0;
+
+ private final Object[] mColors = {Color.BLACK, Color.RED, Color.GREEN, Color.YELLOW,
+ Color.BLUE, Color.MAGENTA, Color.CYAN, Color.WHITE};
+
+ public JCTerminalView(Context c) {
+ super(c);
+ mPaint = new Paint();
+ mPaint.setAntiAlias(mAntialias);
+ mPaint.setColor(mDefaultForeground);
+
+ mCursorPaint = new Paint();
+ mCursorPaint.setAntiAlias(mAntialias);
+ mCursorPaint.setColor(mDefaultForeground);
+ mCursorPaint.setXfermode(new PixelXorXfermode(mDefaultBackground));
+
+ setFont(Typeface.MONOSPACE);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mBitmap != null) {
+ canvas.drawBitmap(mBitmap, 0, 0, null);
+
+ if (mCharHeight > 0 && y > mCharHeight) {
+ // Invert pixels for cursor position.
+ canvas.drawRect(x, y - mCharHeight, x + mCharWidth, y, mCursorPaint);
+ }
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ Log.d("SSH/TerminalView", "onSizeChanged called");
+ Bitmap newBitmap = Bitmap.createBitmap(w, h, false);
+ Canvas newCanvas = new Canvas();
+
+ newCanvas.setDevice(newBitmap);
+
+ if (mBitmap != null)
+ newCanvas.drawBitmap(mBitmap, 0, 0, mPaint);
+
+ mBitmap = newBitmap;
+ mCanvas = newCanvas;
+
+ setSize(w, h);
+ }
+
+ private void setSize(int w, int h) {
+ int column = w / getCharWidth();
+ int row = h / getCharHeight();
+
+ mTermWidth = column;
+ mTermHeight = row;
+
+ if (emulator != null)
+ emulator.reset();
+
+ clear_area(0, 0, w, h);
+
+ // TODO: finish this method
+ }
+
+ private void setFont(Typeface typeface) {
+ mPaint.setTypeface(typeface);
+ mPaint.setTextSize(8);
+ FontMetricsInt fm = mPaint.getFontMetricsInt();
+ mDescent = fm.descent;
+
+ float[] widths = new float[1];
+ mPaint.getTextWidths("X", widths);
+ mCharWidth = (int)widths[0];
+
+ // Is this right?
+ mCharHeight = Math.abs(fm.top) + Math.abs(fm.descent);
+ Log.d("SSH", "character height is " + mCharHeight);
+ // mCharHeight += mLineSpace * 2;
+ // mDescent += mLineSpace;
+ }
+
+ public void beep() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void clear() {
+ mPaint.setColor(getBackgroundColor());
+ mCanvas.drawRect(0, 0, mCanvas.getBitmapWidth(),
+ mCanvas.getBitmapHeight(), mPaint);
+ mPaint.setColor(getForegroundColor());
+ }
+
+ private int getBackgroundColor() {
+ if (mReverse)
+ return mForeground;
+ return mBackground;
+ }
+
+ private int getForegroundColor() {
+ if (mReverse)
+ return mBackground;
+ return mForeground;
+ }
+
+ public void clear_area(int x1, int y1, int x2, int y2) {
+ mPaint.setColor(getBackgroundColor());
+ if (mCanvas != null)
+ mCanvas.drawRect(x1, y1, x2, y2, mPaint);
+ mPaint.setColor(getForegroundColor());
+ }
+
+ public void drawBytes(byte[] buf, int s, int len, int x, int y) {
+ String chars = null;
+ try {
+ chars = new String(buf, "ASCII");
+ drawString(chars.substring(s, s+len), x, y);
+ } catch (UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ Log.e("SSH", "Can't convert bytes to ASCII");
+ }
+ }
+
+ public void drawString(String str, int x, int y) {
+ mPaint.setFakeBoldText(mBold);
+ mPaint.setUnderlineText(mUnderline);
+ mCanvas.drawText(str, x, y - mDescent, mPaint);
+ }
+
+ public void draw_cursor() {
+ postInvalidate();
+ }
+
+ public int getCharHeight() {
+ return mCharHeight;
+ }
+
+ public int getCharWidth() {
+ return mCharWidth;
+ }
+
+ public Object getColor(int index) {
+ if (mColors == null || index < 0 || mColors.length <= index)
+ return null;
+ return mColors[index];
+ }
+
+ public int getColumnCount() {
+ return mTermWidth;
+ }
+
+ public int getRowCount() {
+ return mTermHeight;
+ }
+
+ public int getTermHeight() {
+ return mTermHeight * mCharHeight;
+ }
+
+ public int getTermWidth() {
+ return mTermWidth * mCharWidth;
+ }
+
+ public void redraw(int x, int y, int width, int height) {
+ //invalidate(x, y, x+width, y+height);
+ postInvalidate();
+ }
+
+ public void resetAllAttributes() {
+ mBold = false;
+ mUnderline = false;
+ mReverse = false;
+
+ mBackground = mDefaultBackground;
+ mForeground = mDefaultForeground;
+
+ if (mPaint != null)
+ mPaint.setColor(mForeground);
+ }
+
+ public void scroll_area(int x, int y, int w, int h, int dx, int dy) {
+ // TODO: make scrolling more efficient (memory-wise)
+ mCanvas.drawBitmap(Bitmap.createBitmap(mBitmap, x, y, w, h), x+dx, y+dy, null);
+ }
+
+ private int toColor(Object o) {
+ if (o instanceof Integer) {
+ return ((Integer)o).intValue();
+ }
+
+ if (o instanceof String) {
+ return Color.parseColor((String)o);
+ }
+
+ return Color.WHITE;
+ }
+
+ public void setBackGround(Object background) {
+ mBackground = toColor(background);
+ }
+
+ public void setBold() {
+ mBold = true;
+ }
+
+ public void setCursor(int x, int y) {
+ // Make sure we don't go outside the bounds of the window.
+ this.x = Math.max(
+ Math.min(x, getWidth() - mCharWidth),
+ 0);
+ this.y = Math.max(
+ Math.min(y, getHeight()),
+ mCharHeight);
+ }
+
+ public void setDefaultBackGround(Object background) {
+ mDefaultBackground = toColor(background);
+ }
+
+ public void setDefaultForeGround(Object foreground) {
+ mDefaultForeground = toColor(foreground);
+ }
+
+ public void setForeGround(Object foreground) {
+ mForeground = toColor(foreground);
+ }
+
+ public void setReverse() {
+ mReverse = true;
+ if (mPaint != null)
+ mPaint.setColor(getForegroundColor());
+ }
+
+ public void setUnderline() {
+ mUnderline = true;
+ }
+
+ public void start(InputStream in, OutputStream out) {
+ emulator = new EmulatorVT100(this, in);
+ emulator.reset();
+ emulator.start();
+
+ clear();
+ }
+
+ public byte[] getKeyCode(int keyCode, int meta) {
+ if (keyCode == KeyEvent.KEYCODE_NEWLINE)
+ return emulator.getCodeENTER();
+ else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT)
+ return emulator.getCodeLEFT();
+ else if (keyCode == KeyEvent.KEYCODE_DPAD_UP)
+ return emulator.getCodeUP();
+ else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
+ return emulator.getCodeDOWN();
+ else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT)
+ return emulator.getCodeRIGHT();
+ else
+ return null;
+ }
+}
diff --git a/src/org/theb/ssh/JTATerminalView.java b/src/org/theb/ssh/JTATerminalView.java
new file mode 100644
index 0000000..2238f02
--- /dev/null
+++ b/src/org/theb/ssh/JTATerminalView.java
@@ -0,0 +1,323 @@
+package org.theb.ssh;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import de.mud.terminal.SoftFont;
+import de.mud.terminal.VDUBuffer;
+import de.mud.terminal.VDUDisplay;
+import de.mud.terminal.vt320;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.Paint.FontMetricsInt;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+
+public class JTATerminalView extends View implements VDUDisplay, Terminal, Runnable {
+ private Paint paint;
+ private Canvas canvas;
+ private Bitmap bitmap;
+
+ protected vt320 emulation;
+ private VDUBuffer buffer;
+
+ private InputStream in;
+ private OutputStream out;
+
+ private String encoding = "ASCII";
+ private SoftFont sf = new SoftFont();
+
+ private Thread reader = null;
+
+ private int charWidth;
+ private int charHeight;
+ private int charDescent;
+
+ private int termWidth;
+ private int termHeight;
+
+ private int color[] = {
+ Color.BLACK,
+ Color.RED,
+ Color.GREEN,
+ Color.YELLOW,
+ Color.BLUE,
+ Color.MAGENTA,
+ Color.CYAN,
+ Color.WHITE,
+ };
+
+ private final static int COLOR_FG_STD = 7;
+ private final static int COLOR_BG_STD = 0;
+
+ public JTATerminalView(Context context) {
+ super(context);
+
+ paint = new Paint();
+ paint.setAntiAlias(true);
+ setFont(Typeface.MONOSPACE, 8);
+
+ emulation = new vt320() {
+ public void write(byte[] b) {
+ try {
+ JTATerminalView.this.write(b);
+ } catch (IOException e) {
+ Log.e("SSH", "couldn't write" + b.toString());
+ reader = null;
+ }
+ }
+
+ public void sendTelnetCommand(byte cmd) {
+ // TODO: implement telnet command sending
+ }
+
+ public void setWindowSize(int c, int r) {
+ // TODO: implement window sizing
+ }
+ };
+
+ setVDUBuffer(emulation);
+ emulation.setDisplay(this);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (bitmap != null) {
+ canvas.drawBitmap(bitmap, 0, 0, null);
+ /*
+ if (charHeight > 0 && y > charHeight) {
+ // Invert pixels for cursor position.
+ Bitmap cursor = Bitmap.createBitmap(mBitmap, x, y - mCharHeight, mCharWidth, mCharHeight);
+ for (int cy = 0; cy < mCharHeight; cy++)
+ for (int cx = 0; cx < mCharWidth; cx++)
+ cursor.setPixel(cx, cy, (~cursor.getPixel(cx, cy) & 0xFFFFFFFF) | 0xFF000000);
+ canvas.drawBitmap(cursor, x, y - mCharHeight, null);
+ cursor = null;
+ }
+ */
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ Log.d("SSH/TerminalView", "onSizeChanged called");
+ Bitmap newBitmap = Bitmap.createBitmap(w, h, false);
+ Canvas newCanvas = new Canvas();
+
+ newCanvas.setDevice(newBitmap);
+
+ if (bitmap != null)
+ newCanvas.drawBitmap(bitmap, 0, 0, paint);
+
+ bitmap = newBitmap;
+ canvas = newCanvas;
+
+ setSize(w, h);
+ }
+
+ private void setSize(int w, int h) {
+ termWidth = w / charWidth;
+ termHeight = h / charHeight;
+
+ buffer.setScreenSize(termWidth, buffer.height = termHeight, true);
+ }
+
+ private void setFont(Typeface typeface, int size) {
+ paint.setTypeface(typeface);
+ paint.setTextSize(size);
+
+ FontMetricsInt fm = paint.getFontMetricsInt();
+
+ charDescent = fm.descent;
+
+ float[] widths = new float[1];
+ paint.getTextWidths("X", widths);
+ charWidth = (int)widths[0];
+
+ charHeight = Math.abs(fm.top) + Math.abs(fm.descent);
+ }
+
+ public void write(byte[] b) throws IOException {
+ Log.e("SSH/JTATerm/write", "Trying to write" + b.toString());
+ out.write(b);
+ }
+
+ public int getColumnCount() {
+ return termWidth;
+ }
+
+ public InputStream getInput() {
+ return in;
+ }
+
+ public byte[] getKeyCode(int keyCode, int meta) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_NEWLINE:
+ emulation.keyTyped(vt320.KEY_ENTER, ' ', meta);
+ break;
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ emulation.keyPressed(vt320.KEY_LEFT, ' ', meta);
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ emulation.keyPressed(vt320.KEY_UP, ' ', meta);
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ emulation.keyPressed(vt320.KEY_DOWN, ' ', meta) ;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ emulation.keyPressed(vt320.KEY_RIGHT, ' ', meta);
+ break;
+ }
+ return null;
+ }
+
+ public OutputStream getOutput() {
+ return out;
+ }
+
+ public int getRowCount() {
+ return termHeight;
+ }
+
+ private int darken(int color) {
+ return Color.argb(0xFF,
+ (int)(Color.red(color) * 0.8),
+ (int)(Color.green(color) * 0.8),
+ (int)(Color.blue(color) * 0.8)
+ );
+ }
+
+ /*
+ private int brighten(int color) {
+ return Color.argb(0xFF,
+ (int)(Color.red(color) * 1.2),
+ (int)(Color.green(color) * 1.2),
+ (int)(Color.blue(color) * 1.2)
+ );
+ }
+ */
+
+ public void redraw() {
+ // Make sure the buffer is in the center of the screen.
+ int xoffset = (getWidth() - buffer.width * charWidth) / 2;
+ int yoffset = (getHeight() - buffer.height * charHeight) / 2;
+
+ // Draw the mouse-selection
+ //int selectStartLine = selectBegin.y - buffer.windowBase;
+ //int selectEndLine = selectEnd.y - buffer.windowBase;
+
+ int fg, bg;
+
+ for (int l = 0; l < buffer.height; l++) {
+ if (!buffer.update[0] && !buffer.update[l + 1]) continue;
+
+ for (int c = 0; c < buffer.width; c++) {
+ int addr = 0;
+ int currAttr = buffer.charAttributes[buffer.windowBase + l][c];
+
+ fg = darken(color[COLOR_FG_STD]);
+ bg = darken(color[COLOR_BG_STD]);
+
+ if ((currAttr & VDUBuffer.COLOR_FG) != 0)
+ fg = darken(color[((currAttr & VDUBuffer.COLOR_FG) >> VDUBuffer.COLOR_FG_SHIFT) - 1]);
+ if ((currAttr & VDUBuffer.COLOR_BG) != 0)
+ bg = darken(darken(color[((currAttr & VDUBuffer.COLOR_BG) >> VDUBuffer.COLOR_BG_SHIFT) - 1]));
+ paint.setFakeBoldText((currAttr & VDUBuffer.BOLD) != 0);
+
+ if ((currAttr & VDUBuffer.LOW) != 0)
+ fg = darken(fg);
+
+ if ((currAttr & VDUBuffer.INVERT) != 0) {
+ int swapc = bg;
+ bg = fg;
+ fg = swapc;
+ }
+
+ // If this character is in the special font, print it and continue to the next character.
+ if (sf.inSoftFont(buffer.charArray[buffer.windowBase + l][c])) {
+ paint.setColor(bg);
+ canvas.drawRect(c * charWidth + xoffset, l * charHeight + yoffset,
+ c * (charWidth + 1) + xoffset, (l+1) * charHeight + yoffset, paint);
+ paint.setColor(fg);
+ paint.setUnderlineText((currAttr & VDUBuffer.UNDERLINE) != 0);
+ if ((currAttr & VDUBuffer.INVISIBLE) == 0)
+ sf.drawChar(canvas, paint, buffer.charArray[buffer.windowBase + l][c], xoffset + c * charWidth, l * charHeight + yoffset, charWidth, charHeight);
+ continue;
+ }
+
+ // Determine the amount of continuous characters with the same settings and print them all at once.
+ while ((c + addr < buffer.width) &&
+ ((buffer.charArray[buffer.windowBase + l][c + addr] < ' ') ||
+ (buffer.charAttributes[buffer.windowBase + l][c + addr] == currAttr)) &&
+ !sf.inSoftFont(buffer.charArray[buffer.windowBase + l][c + addr])) {
+ if (buffer.charArray[buffer.windowBase + l][c + addr] < ' ') {
+ buffer.charArray[buffer.windowBase + l][c + addr] = ' ';
+ buffer.charAttributes[buffer.windowBase + l][c + addr] = 0;
+ continue;
+ }
+ addr++;
+ }
+
+ paint.setColor(bg);
+ canvas.drawRect(c * charWidth + xoffset, l * charHeight + yoffset,
+ addr * (charWidth + 1) + xoffset, (l+1) * charHeight + yoffset, paint);
+ paint.setColor(fg);
+
+ paint.setUnderlineText((currAttr & VDUBuffer.UNDERLINE) != 0);
+ if ((currAttr & VDUBuffer.INVISIBLE) == 0)
+ canvas.drawText(buffer.charArray[buffer.windowBase + l],
+ c, addr,
+ c * charWidth + xoffset,
+ (l + 1) * charHeight - charDescent + yoffset,
+ paint);
+
+ c += addr - 1;
+ }
+ }
+
+ buffer.update[0] = false;
+
+ postInvalidate();
+ }
+
+ public void updateScrollBar() {
+ // TODO Auto-generated method stub
+ }
+
+ public void start(InputStream in, OutputStream out) {
+ this.in = in;
+ this.out = out;
+
+ reader = new Thread(this);
+ reader.start();
+ }
+
+ public VDUBuffer getVDUBuffer() {
+ return buffer;
+ }
+
+ public void setVDUBuffer(VDUBuffer buffer) {
+ this.buffer = buffer;
+ }
+
+ public void run() {
+ byte[] b = new byte[256];
+ int n = 0;
+ while (n >= 0)
+ try {
+ n = in.read(b);
+ if (n > 0) emulation.putString(new String(b, 0, n, encoding));
+ redraw();
+ } catch (IOException e) {
+ reader = null;
+ break;
+ }
+ }
+}
diff --git a/src/org/theb/ssh/PasswordDialog.java b/src/org/theb/ssh/PasswordDialog.java
index 87839b7..faf636a 100644
--- a/src/org/theb/ssh/PasswordDialog.java
+++ b/src/org/theb/ssh/PasswordDialog.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
package org.theb.ssh;
import android.app.Activity;
diff --git a/src/org/theb/ssh/PreferencesDialog.java b/src/org/theb/ssh/PreferencesDialog.java
new file mode 100644
index 0000000..06bc229
--- /dev/null
+++ b/src/org/theb/ssh/PreferencesDialog.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.theb.ssh;
+
+import android.app.Dialog;
+import android.content.Context;
+
+public class PreferencesDialog extends Dialog {
+
+ public PreferencesDialog(Context context) {
+ super(context);
+ // TODO Auto-generated constructor stub
+ }
+
+ public PreferencesDialog(Context context, int theme) {
+ super(context, theme);
+ // TODO Auto-generated constructor stub
+ }
+
+ public PreferencesDialog(Context context, boolean cancelable,
+ OnCancelListener cancelListener) {
+ super(context, cancelable, cancelListener);
+ // TODO Auto-generated constructor stub
+ }
+
+}
diff --git a/src/org/theb/ssh/SecureShell.java b/src/org/theb/ssh/SecureShell.java
index 31625f9..8d4dda6 100644
--- a/src/org/theb/ssh/SecureShell.java
+++ b/src/org/theb/ssh/SecureShell.java
@@ -1,12 +1,30 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
package org.theb.ssh;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
-import java.util.concurrent.Semaphore;
import org.theb.provider.HostDb;
+import com.trilead.ssh2.ConnectionMonitor;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@@ -17,22 +35,16 @@ import android.os.Handler;
import android.text.method.KeyCharacterMap;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.View;
import android.view.Window;
-import android.widget.TextView;
-
-import com.trilead.ssh2.ChannelCondition;
-import com.trilead.ssh2.Connection;
-import com.trilead.ssh2.ConnectionMonitor;
-import com.trilead.ssh2.Session;
-public class SecureShell extends Activity {
- private TextView mOutput;
+public class SecureShell extends Activity implements FeedbackUI, ConnectionMonitor {
private ConnectionThread mConn;
- private String mBuffer;
- private KeyCharacterMap mKMap;
+ // Activities we support.
static final int PASSWORD_REQUEST = 0;
+ // Database projection indices.
private static final int HOSTNAME_INDEX = 1;
private static final int USERNAME_INDEX = 2;
private static final int PORT_INDEX = 3;
@@ -46,6 +58,15 @@ public class SecureShell extends Activity {
private Cursor mCursor;
+ // Map to convert from keyboard presses to actual characters.
+ private KeyCharacterMap mKMap;
+
+ // Terminal window
+ private Terminal mTerminal;
+
+ // We change the meta state when the user presses the center button.
+ private boolean mMetaState = false;
+
// Store the username, hostname, and port from the database.
private String mHostname;
private String mUsername;
@@ -56,241 +77,21 @@ public class SecureShell extends Activity {
private boolean mIsWaiting;
private String mWaitingTitle;
private String mWaitingMessage;
-
- // Connection lost reason.
- private String mDisconnectReason;
-
- // This is for the password dialog.
- Semaphore sPass;
- String mPassword = null;
-
- Connection conn;
- Session sess;
- InputStream stdin;
- InputStream stderr;
- OutputStream stdout;
- int x;
- int y;
-
+
final Handler mHandler = new Handler();
- final Runnable mUpdateView = new Runnable() {
- public void run() {
- updateViewInUI();
- }
- };
-
- class ConnectionThread extends Thread {
- String hostname;
- String username;
- int port;
-
- char[][] lines;
- int posy = 0;
- int posx = 0;
-
- public ConnectionThread(String hostname, String username, int port) {
- this.hostname = hostname;
- this.username = username;
- this.port = port;
- }
-
- public void run() {
- conn = new Connection(hostname, port);
-
- conn.addConnectionMonitor(mConnectionMonitor);
-
- setWaiting(true, "Connection",
- "Connecting to " + hostname + "...");
-
- Log.d("SSH", "Starting connection attempt...");
-
- try {
- conn.connect(new InteractiveHostKeyVerifier());
-
- setWaiting(true, "Authenticating",
- "Trying to authenticate...");
-
- Log.d("SSH", "Starting authentication...");
-
-// boolean enableKeyboardInteractive = true;
-// boolean enableDSA = true;
-// boolean enableRSA = true;
-
- while (true) {
- /*
- if ((enableDSA || enableRSA ) &&
- mConn.isAuthMethodAvailable(username, "publickey");
- */
-
- if (conn.isAuthMethodAvailable(username, "password")) {
- Log.d("SSH", "Trying password authentication...");
- setWaiting(true, "Authenticating",
- "Trying to authenticate using password...");
-
- // Set a semaphore that is unset by the returning dialog.
- sPass = new Semaphore(0);
- askPassword();
-
- // Wait for the user to answer.
- sPass.acquire();
- sPass = null;
- if (mPassword == null)
- continue;
-
- boolean res = conn.authenticateWithPassword(username, mPassword);
- if (res == true)
- break;
-
- continue;
- }
-
- throw new IOException("No supported authentication methods available.");
- }
-
- Log.d("SSH", "Opening session...");
- setWaiting(true, "Session", "Requesting shell...");
-
- sess = conn.openSession();
-
- y = (int)(mOutput.getHeight() / mOutput.getLineHeight());
- // TODO: figure out how to get the width of monospace font characters.
- x = y * 3;
- Log.d("SSH", "Requesting PTY of size " + x + "x" + y);
-
- sess.requestPTY("dumb", x, y, 0, 0, null);
-
- Log.d("SSH", "Requesting shell...");
- sess.startShell();
-
- stdout = sess.getStdin();
- stderr = sess.getStderr();
- stdin = sess.getStdout();
-
- setWaiting(false, null, null);
- } catch (IOException e) {
- Log.e("SSH", e.getMessage());
- setWaiting(false, null, null);
- return;
- } catch (InterruptedException e) {
- // This thread is coming to an end. Let us exit.
- Log.e("SSH", "Connection thread interrupted.");
- return;
- }
-
- byte[] buff = new byte[8192];
- lines = new char[y][];
-
- try {
- while (true) {
- if ((stdin.available() == 0) && (stderr.available() == 0)) {
- int conditions = sess.waitForCondition(
- ChannelCondition.STDOUT_DATA
- | ChannelCondition.STDERR_DATA
- | ChannelCondition.EOF, 2000);
- if ((conditions & ChannelCondition.TIMEOUT) != 0)
- continue;
- if ((conditions & ChannelCondition.EOF) != 0)
- if ((conditions &
- (ChannelCondition.STDERR_DATA
- | ChannelCondition.STDOUT_DATA)) == 0)
- break;
- }
-
- if (stdin.available() > 0) {
- int len = stdin.read(buff);
- addText(buff, len);
- }
- if (stderr.available() > 0) {
- int len = stderr.read(buff);
- addText(buff, len);
- }
- }
- } catch (Exception e) {
- Log.e("SSH", "Got exception reading: " + e.getMessage());
- }
- }
-
- public void addText(byte[] data, int len) {
- for (int i = 0; i < len; i++) {
- char c = (char) (data[i] & 0xff);
-
- if (c == 8) { // Backspace, VERASE
- if (posx < 0)
- continue;
- posx--;
- continue;
- }
- if (c == '\r') {
- posx = 0;
- continue;
- }
-
- if (c == '\n') {
- posy++;
- if (posy >= y) {
- for (int k = 1; k < y; k++)
- lines[k - 1] = lines[k];
-
- posy--;
- lines[y - 1] = new char[x];
-
- for (int k = 0; k < x; k++)
- lines[y - 1][k] = ' ';
- }
- continue;
- }
-
- if (c < 32) {
- continue;
- }
-
- if (posx >= x) {
- posx = 0;
- posy++;
- if (posy >= y) {
- posy--;
-
- for (int k = 1; k < y; k++)
- lines[k - 1] = lines[k];
- lines[y - 1] = new char[x];
- for (int k = 0; k < x; k++)
- lines[y - 1][k] = ' ';
- }
- }
-
- if (lines[posy] == null) {
- lines[posy] = new char[x];
- for (int k = 0; k < x; k++)
- lines[posy][k] = ' ';
- }
+ // Tell the user why we disconnected.
+ private String mDisconnectReason;
- lines[posy][posx] = c;
- posx++;
- }
-
- StringBuffer sb = new StringBuffer(x * y);
-
- for (int i = 0; i < lines.length; i++) {
- if (i != 0)
- sb.append('\n');
-
- if (lines[i] != null)
- sb.append(lines[i]);
- }
-
- mBuffer = sb.toString();
- mHandler.post(mUpdateView);
- }
- }
-
@Override
public void onCreate(Bundle savedValues) {
super.onCreate(savedValues);
requestWindowFeature(Window.FEATURE_PROGRESS);
- setContentView(R.layout.secure_shell);
- mOutput = (TextView) findViewById(R.id.output);
+ mTerminal = new JTATerminalView(this);
+
+ // TODO: implement scroll bar on right.
+ setContentView((View)mTerminal);
Log.d("SSH", "using URI " + getIntent().getData().toString());
@@ -307,7 +108,7 @@ public class SecureShell extends Activity {
this.setTitle(title);
- mConn = new ConnectionThread(mHostname, mUsername, mPort);
+ mConn = new TrileadConnectionThread(this, mTerminal, mHostname, mUsername, mPort);
mKMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
@@ -340,10 +141,9 @@ public class SecureShell extends Activity {
}
};
- public String askPassword() {
+ public void askPassword() {
Intent intent = new Intent(this, PasswordDialog.class);
this.startSubActivity(intent, PASSWORD_REQUEST);
- return null;
}
@Override
@@ -351,55 +151,71 @@ public class SecureShell extends Activity {
String data, Bundle extras)
{
if (requestCode == PASSWORD_REQUEST) {
-
- // If the request was cancelled, then we didn't get anything.
- if (resultCode == RESULT_CANCELED)
- mPassword = "";
- else
- mPassword = data;
-
- sPass.release();
+ mConn.setPassword(data);
}
}
@Override
public void onDestroy() {
super.onDestroy();
-
- if (sess != null) {
- sess.close();
- sess = null;
- }
-
- if (conn != null) {
- conn.close();
- conn = null;
- }
+
+ mConn.finish();
+ mConn = null;
finish();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent msg) {
- if (stdout != null) {
- int c = mKMap.get(keyCode, msg.getMetaState());
+ final OutputStream out = mConn.getWriter();
+ if (out != null) {
try {
- stdout.write(c);
+ if (mKMap.isPrintingKey(keyCode)
+ || keyCode == KeyEvent.KEYCODE_SPACE) {
+ int c = mKMap.get(keyCode, msg.getMetaState());
+ if (mMetaState) {
+ // Support CTRL-A through CTRL-Z
+ if (c >= 0x61 && c <= 0x79)
+ c -= 0x60;
+ else if (c >= 0x40 && c <= 0x59)
+ c -= 0x39;
+ mMetaState = false;
+ }
+ out.write(c);
+ } else if (keyCode == KeyEvent.KEYCODE_DEL) {
+ out.write(0x08); // CTRL-H
+ } else if (keyCode == KeyEvent.KEYCODE_NEWLINE
+ || keyCode == KeyEvent.KEYCODE_DPAD_LEFT
+ || keyCode == KeyEvent.KEYCODE_DPAD_UP
+ || keyCode == KeyEvent.KEYCODE_DPAD_DOWN
+ || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ byte[] output = mTerminal.getKeyCode(keyCode, msg.getMetaState());
+ if (output != null)
+ out.write(output);
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ if (mMetaState) {
+ out.write(0x1B); // ESCAPE
+ mMetaState = false;
+ } else {
+ mMetaState = true;
+ }
+ } else {
+ // This is not something we handle.
+ return super.onKeyDown(keyCode, msg);
+ }
+ return true;
} catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ Log.e("SSH", "Can't write to stdout: "+ e.getMessage());
}
}
-
- return super.onKeyDown(keyCode, msg);
- }
-
- public void updateViewInUI() {
- mOutput.setText(mBuffer);
+ return super.onKeyDown(keyCode, msg);
}
final Runnable mDisconnectAlert = new Runnable() {
public void run() {
+ if (SecureShell.this.isFinishing())
+ return;
+
AlertDialog d = AlertDialog.show(SecureShell.this,
"Connection Lost", mDisconnectReason, "Ok", false);
d.show();
@@ -407,11 +223,9 @@ public class SecureShell extends Activity {
}
};
- final ConnectionMonitor mConnectionMonitor = new ConnectionMonitor() {
- public void connectionLost(Throwable reason) {
- Log.d("SSH", "Connection ended.");
- mDisconnectReason = reason.getMessage();
- mHandler.post(mDisconnectAlert);
- }
- };
+ public void connectionLost(Throwable reason) {
+ Log.d("SSH", "Connection ended.");
+ mDisconnectReason = reason.getMessage();
+ mHandler.post(mDisconnectAlert);
+ }
}
diff --git a/src/org/theb/ssh/ShellView.java b/src/org/theb/ssh/ShellView.java
deleted file mode 100644
index 15d783b..0000000
--- a/src/org/theb/ssh/ShellView.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.theb.ssh;
-
-import java.io.IOException;
-
-import com.trilead.ssh2.Connection;
-import com.trilead.ssh2.Session;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.Log;
-import android.widget.EditText;
-import android.widget.TextView;
-
-public class ShellView extends EditText {
-
- private Connection mConn;
- private Session mSess;
-
- private String mHostname;
- private String mUsername;
- private String mPassword;
-
- public ShellView(Context context) {
- super(context);
- // TODO Auto-generated constructor stub
-
- mPassword = "OEfmP07-";
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- append("Connecting... ");
- mConn = new Connection(mHostname);
-
- try {
- mConn.connect(new InteractiveHostKeyVerifier());
- append("OK\n");
- } catch (IOException e) {
- append("Failed.\n");
- Log.e("SSH", e.getMessage());
- append("\nWhoops: " + e.getCause().getMessage() + "\n");
- }
-
- boolean enableKeyboardInteractive = true;
- boolean enableDSA = true;
- boolean enableRSA = true;
-
- try {
- while (true) {
- /*
- if ((enableDSA || enableRSA ) &&
- mConn.isAuthMethodAvailable(username, "publickey");
- */
-
- if (mConn.isAuthMethodAvailable(mUsername, "password")) {
- boolean res = mConn.authenticateWithPassword(mUsername, mPassword);
- if (res == true)
- break;
-
- append("Login failed.\n");
- continue;
- }
-
- throw new IOException("No supported authentication methods available.");
- }
-
- mSess = mConn.openSession();
- append("Logged in as " + mUsername + ".\n");
- } catch (IOException e) {
- Log.e("SSH", e.getMessage());
- }
- append("Exiting\n");
- }
-
-}
diff --git a/src/org/theb/ssh/Terminal.java b/src/org/theb/ssh/Terminal.java
new file mode 100644
index 0000000..1212aa2
--- /dev/null
+++ b/src/org/theb/ssh/Terminal.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.theb.ssh;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public interface Terminal {
+ public int getWidth();
+ public int getHeight();
+ public int getRowCount();
+ public int getColumnCount();
+ public void start(InputStream in, OutputStream out);
+ public byte[] getKeyCode(int keyCode, int meta);
+}
diff --git a/src/org/theb/ssh/TrileadConnectionThread.java b/src/org/theb/ssh/TrileadConnectionThread.java
new file mode 100644
index 0000000..63180b0
--- /dev/null
+++ b/src/org/theb/ssh/TrileadConnectionThread.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
+ *
+ * This file is part of Connectbot.
+ *
+ * Connectbot is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Connectbot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.theb.ssh;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.Semaphore;
+
+import com.trilead.ssh2.Connection;
+import com.trilead.ssh2.ConnectionMonitor;
+import com.trilead.ssh2.Session;
+
+public class TrileadConnectionThread extends ConnectionThread {
+ private String hostname;
+ private String username;
+ private String password;
+ private int port;
+
+ private Connection connection;
+ private Session session;
+
+ private InputStream stdOut;
+ private OutputStream stdIn;
+
+ private Semaphore sPass;
+
+ protected FeedbackUI ui;
+ protected Terminal term;
+
+ public TrileadConnectionThread(FeedbackUI ui, Terminal term, String hostname, String username, int port) {
+ super(ui, hostname, username, port);
+ this.ui = ui;
+ this.term = term;
+ this.hostname = hostname;
+ this.username = username;
+ this.port = port;
+ }
+
+ @Override
+ public void finish() {
+ if (session != null) {
+ session.close();
+ session = null;
+ }
+
+ if (connection != null) {
+ connection.close();
+ connection = null;
+ }
+ }
+
+ @Override
+ public InputStream getReader() {
+ return stdOut;
+ }
+
+ @Override
+ public OutputStream getWriter() {
+ return stdIn;
+ }
+
+ @Override
+ public void run() {
+ connection = new Connection(hostname, port);
+
+ connection.addConnectionMonitor((ConnectionMonitor) ui);
+
+ ui.setWaiting(true, "Connection", "Connecting to " + hostname + "...");
+
+ try {
+ connection.connect(new InteractiveHostKeyVerifier());
+
+ ui.setWaiting(true, "Authenticating", "Trying to authenticate...");
+
+ // boolean enableKeyboardInteractive = true;
+ // boolean enableDSA = true;
+ // boolean enableRSA = true;
+
+ while (true) {
+ /*
+ * if ((enableDSA || enableRSA ) &&
+ * mConn.isAuthMethodAvailable(username, "publickey");
+ */
+
+ if (connection.isAuthMethodAvailable(username, "password")) {
+ ui.setWaiting(true, "Authenticating",
+ "Trying to authenticate using password...");
+
+ // Set a semaphore that is unset by the returning dialog.
+ sPass = new Semaphore(0);
+ ui.askPassword();
+
+ // Wait for the user to answer.
+ sPass.acquire();
+ sPass = null;
+ if (password == null)
+ continue;
+
+ boolean res = connection.authenticateWithPassword(username,
+ password);
+ password = null;
+ if (res == true)
+ break;
+
+ continue;
+ }
+
+ throw new IOException(
+ "No supported authentication methods available.");
+ }
+
+ ui.setWaiting(true, "Session", "Requesting shell...");
+
+ session = connection.openSession();
+
+ session.requestPTY("vt100",
+ term.getColumnCount(), term.getRowCount(),
+ term.getWidth(), term.getHeight(),
+ null);
+
+ session.startShell();
+
+ stdIn = session.getStdin();
+ // stderr = session.getStderr();
+ stdOut = session.getStdout();
+
+ ui.setWaiting(false, null, null);
+ } catch (IOException e) {
+ ui.setWaiting(false, null, null);
+ return;
+ } catch (InterruptedException e) {
+ // This thread is coming to an end. Let us exit.
+ return;
+ }
+
+ term.start(stdOut, stdIn);
+ }
+
+ @Override
+ public void setPassword(String password) {
+ if (password == null)
+ this.password = "";
+ else
+ this.password = password;
+ sPass.release();
+ }
+}